class Mycompute
def initialize(str)
#str=str
end
def values
##result=#str
end
def up
##result.upcase
end
end
irb(main):012:0> Mycompute.new("Abc").values
=> "Abc"
irb(main):013:0>
irb(main):014:0* Mycompute.new("Abc").up
=> "ABC"
irb(main):015:0> Mycompute.new("Abc").values.up
NoMethodError: undefined method `up' for "Abc":String
from (irb):15
from :0
How can I make Mycompute.new("Abc").values.up work?
The object returned from values need have up.
class Mycompute
def initialize(str)
#str=str
end
def values
##result=#str
def ##result.up
self.upcase
end
##result
end
def up
##result.upcase
end
end
This works well.
Mycompute.new("Abc").values #=> "Abc"
Mycompute.new("Abc").up #=> "ABC"
Mycompute.new("Abc").values.up #=> "ABC"
Related
I want to write a method which takes one parameter and creates another method, named with this parameter. Here is my code
class Class
def createMethod(attr_name)
attr_name = attr_name.to_s
class_eval %Q{
def #{attr_name}
puts "bar"
end
}
end
end
p Class.new.createMethod("foo").respond_to?(:foo)
Unfortunately, respond_to?(:foo) evaluates to false. What's wrong?
This is because class_eval is a class method and you're calling it in the context of an instance. You can do this instead:
class Class
def createMethod(attr_name)
attr_name = attr_name.to_s
self.class.class_eval %Q{
def #{attr_name}
puts "bar"
end
}
self # Return yourself if you want to allow chaining methods
end
end
Here's the output from irb when doing this:
irb(main):001:0> class Class
irb(main):002:1> def createMethod(attr_name)
irb(main):003:2> attr_name = attr_name.to_s
irb(main):004:2> self.class.class_eval %Q{
irb(main):005:2" def #{attr_name}
irb(main):006:2" puts "bar"
irb(main):007:2" end
irb(main):008:2" }
irb(main):009:2> end
irb(main):010:1> end
=> nil
irb(main):011:0> clazz = Class.new
=> #<Class:0x007fd86495cd58>
irb(main):012:0> clazz.respond_to?(:foo)
=> false
irb(main):013:0> clazz.createMethod("foo")
=> nil
irb(main):014:0> clazz.respond_to?(:foo)
=> true
I'm doing the following, and expecting TestClass.my_var to return"my_var_here":
irb(main):001:0> def create_a_class class_name, my_var
irb(main):002:1> klass = Object.const_set class_name, Class.new
irb(main):003:1> klass.class_variable_set :##my_var, my_var
irb(main):004:1> klass.instance_eval do
irb(main):005:2* def my_var
irb(main):006:3> ##my_var
irb(main):007:3> end
irb(main):008:2> end
irb(main):009:1> klass
irb(main):010:1> end
=> nil
irb(main):011:0> create_a_class "TestClass", "my_var_here"
=> TestClass
Instead, I get this:
irb(main):012:0> TestClass.my_var
(irb):6: warning: class variable access from toplevel
NameError: uninitialized class variable ##my_var in Object
from (irb):6:in `my_var'
from (irb):12
from C:/Ruby193/bin/irb:12:in `<main>'
What am I doing wrong? Any input would be appreciated.
EDIT: I've tried doing it like this and it seems to work, but it doesn't really feel like The Ruby Way™ of doing it (also I'd rather not have those pesky warnings)
irb(main):001:0> def create_a_class class_name, _my_var
irb(main):002:1> klass = Object.const_set class_name, Class.new
irb(main):003:1> klass.instance_eval do
irb(main):004:2* ##my_var = _my_var
irb(main):005:2> def my_var
irb(main):006:3> ##my_var
irb(main):007:3> end
irb(main):008:2> end
irb(main):009:1> klass
irb(main):010:1> end
=> nil
irb(main):011:0> create_a_class "TestClass", "my_var_here"
(irb):4: warning: class variable access from toplevel
=> TestClass
irb(main):012:0> TestClass.my_var
(irb):6: warning: class variable access from toplevel
=> "my_var_here"
First of all? Why are you using class variables? You know you can use instance variables on classes too? They are much more predictable.
Class variables are looked up lexically:
class Foo
##a = 1
end
class Bar
##a = 2
def Foo.a; ##a end
end
p Foo.a # => 2
If you really want to use class variables, then you'll have to use #eval (of some form) to define the method:
def create_a_class class_name, my_var
klass = Object.const_set class_name, Class.new
klass.class_variable_set :##my_var, my_var
klass.class_eval <<-RUBY
def self.my_var
##my_var
end
RUBY
klass
end
create_a_class "Name", "var"
p Name.my_var
Here is an example:
class MyClass
end
obj = MyClass.new
obj.instance_eval do
def hello
"hello"
end
end
obj.hello
# => "hello"
obj.methods.grep "hello"
# => ["hello"]
MyClass.instance_methods.grep "hello"
# => []
MyClass's instance methods don't contain 'hello' method, so My question is where Ruby stores the method defined in instance_eval()?
Look at this:
obj = MyClass.new
def obj.hello
"hello"
end
obj.hello #=> "hello"
obj.singleton_methods #=> [:hello]
obj.methods.grep :hello #=> [:hello]
obj.instance_eval do
def hello2 ; end
end #
obj.singleton_methods #=> [:hello, :hello2]
As you can see instead of using instance_eval you can also define a method directly on an object. In both cases they end up in the object's singleton class (eigenclass), which can be accessed via obj.singleton_class in Ruby 1.9 and the class << self ; self; end idiom in Ruby 1.8.
I have a class like:
class Configuration
def self.files
##files ||= Array.new
end
end
Now instead of doing this:
irb(main):001:0> Configuration.files
=> [file, file, file]
I would like to be able to do this:
irb(main):001:0> Configuration
=> [file, file, file]
But I can't figure out how, any ideas?
#glenn jackman:
I was thinking of adding extra methods to a 'Configuration' constant that's a hash. So if I had...
Configuration = Hash.new
Configuration[:foo] = 'bar'
I wanted to be able to save this Configuration hash constant to be able to dump to and load from a YAML file I wanted to be able to use...
Configuration.load
Configuration.save
I wanted the Configuration class to look like
class Configuration
def self.save
open('config.yml', 'w') {|f| YAML.dump( self , f)}
end
def self.load
open('config.yml') {|f| YAML.load(f)}
end
end
You could possibly get the effect you are looking for by adding a method to the top level object which implicitly calls Configuration.files, but you can't really make a reference to a class invoke a method on it. You can alias the method to something shorter, but you will need to call something.
irb's top level just calls 'inspect' on the result, so by overriding it you can customize what you see in irb:
$ irb
>> class Configuration
>> def self.files
>> ##files ||= Array.new
>> end
>> def self.inspect
>> ##files.inspect
>> end
>> end
=> nil
>> Configuration.files << 1 << 2 << 3
=> [1, 2, 3]
>> Configuration
=> [1, 2, 3]
You could do something like this:
class Configuration
(class << self; self; end).module_eval do
def files
['foo','bar','baz']
end
def to_s
files
end
end
end
This would define the Configuration.files method and say that the to string conversion would return the result of that method. But I am really not sure why you would want to do this. It seems quite wrong.
wpc#wpc-laptop:~$ irb
irb(main):001:0> 'a'
=> a
irb(main):002:0> def A
irb(main):003:1> end
=> nil
irb(main):004:0> A
NameError: uninitialized constant A
from (irb):4
from :0
irb(main):005:0> class A
irb(main):006:1> end
=> nil
irb(main):007:0> A
=> A
irb(main):008:0> class A
irb(main):009:1> (class ['g']
irb(main):012:3> end
irb(main):013:2> def to_s
irb(main):014:3> g
irb(main):015:3> end
irb(main):016:2> end
irb(main):017:1> end
=> nil
irb(main):018:0> A
=> g
irb(main):019:0> class B
irb(main):020:1> class def to_s
irb(main):022:3> 'g'
irb(main):023:3> end
irb(main):024:2> end
irb(main):025:1> end
=> nil
irb(main):026:0> B
=> g
irb(main):027:0> class B
irb(main):028:1> class def files
irb(main):030:3> ['a','b','c']
irb(main):031:3> end
irb(main):032:2> def to_s
irb(main):033:3> files
irb(main):034:3> end
irb(main):035:2> end
irb(main):036:1> end
=> nil
irb(main):037:0> B
=> abc
The right solution is to using the class' method of to_s, but what it return is only the string; and then you can set the inspect for using. See the follows' detail for help.
class A
class<<self
def to_s
......
end
end
end
Consider the following:
irb(main):001:0> class A
irb(main):002:1> def initialize
irb(main):003:2> #string = "my string"
irb(main):004:2> end
irb(main):005:1> def to_s
irb(main):006:2> puts #string
irb(main):007:2> end
irb(main):008:1> end
=> nil
irb(main):009:0> a = A.new
=> #<A:0x2ea606c #string="my string">
irb(main):010:0> puts a
my string
#<A:0x2ea606c>
=> nil
When 'puts' outputs the string my does it also append the refference of the object ?
Is there anyway to get rid of this behavior? What I want outputed is justs the string #string as defined in the classes 'to_s' method
Thanks,
RM
You want your to_s method to just return #string, not do puts #string.