Reputation: 890
Here's an example of a script that I want to be able to support:
class Testing
include Dialect
url_is 'http://localhost:9292'
end
@page = Testing.new
@page.view
The things to note here are:
The url_is() method is going to set a @url variable. The view() method ideally would be able to read that variable. That is what I don't seem to be able to do. Here is the code that supports the above script:
module Dialect
module Generator
module Assertion
def url_is(url)
@url = url
end
end
end
end
module Dialect
def self.included(caller)
caller.extend Dialect::Generator::Assertion
end
def view
puts "#{@url}"
end
end
Here you can see that when Dialect is included, I have an included method that extends my Assertion module. That allows url_is() to work and url_is() does set the instance variable. You can also see I define view() which I want to be able to access that @url variable.
It's the latter part that's not happening. I get why in that I'm trying to read a variable from the Dialect::Generator::Assertion module in the Dialect module but I'm not sure what the best approach is to allow this.
I investigated module and class variable scope and Ruby mixins and instance variables but I haven't found anything that I can determine deals with the situation I'm describing.
Upvotes: 2
Views: 942
Reputation: 22325
I think you're getting confused by the class instance variable @view
.
When you access an instance variable, the "instance" being referred to is self
. In an instance method, self
is the instance of the class (as you would expect). In a class, self
is the class itself (an instance of Class
)! This should illustrate the distinction:
class Foo
@x = 0
def initialize
@x = 1
end
def self.x
@x
end
def x
@x
end
end
Foo.x # 0
Foo.new.x # 1
Foo.x # still 0, they are entirely separate variables
When you extend Dialect::Generator::Assertion
, url_is
is added as a class method to Test
, so @url
is being set as an instance variable for Test
itself. But when you include Dialect
, view
is added as an instance method to Test
so the @url
it is accessing is for an instance of Test
.
In the view
method, you can simply specify that you need the class version of the variable
def view
self.class.class_eval { "#{@url}" }
end
Upvotes: 2