Maybe it's not wise question... but I have a one.
I was playing with Ruby and tried to create methods with a dynamic names in a loop, like this:
class Test
.....
class methods
.....
for i in 1..100
def method_#{i}
my_hash[:test].first[i]
end
end
end
I noticed that's impossible, so... Is there any solution using a :define_method, or :send to solve my problem and gets methods like:
method_0, method_1, method_2 etc. which return my_hash[:test].first[1], my_hash[:test].first[2] etc. ?
You can do it using define_method. Here is the code:
class Test
.....
class methods
.....
1.upto(100) do |num|
define_method("method_#{num}") do
my_hash[:test].first[num]
end
end
end
Related
I want to define methods dynamically using an array of strings.
Here is a simple piece of code that should achieve that.
class SomeClass
attr_accessor :my_array
def initialize(user, record)
#my_array=[]
end
my_array.each do |element|
alias_method "#{element}?".to_sym, :awesome_method
end
def awesome_method
puts 'awesome'
end
end
When I instantiate this class in the console, I get the following error
NoMethodError (undefined method `each' for nil:NilClass)
What is wrong with this code and how to make it work. any help highly appreciated :)
Edit 1:
What I ultimately want to achieve is to inherit from SomeClass and override my_array in the child class to dynamically define methods with its attributes like so
class OtherClass < SomeClass
my_array = %w[method1 method2 method3]
# Some mechanism to over write my_array.
end
And then use self.inherited to dynamically define methods in child class.
Is there a good way to achieve this?
In your code, you use an instance variable (#my_array) and an attr_accessor over it, and then try to access my_array from class level (that is, from the body of the class definition, outside of any methods). But instance variables only exist at instance level, so it is not available in the class scope.
One solution (the natural one, and the one which you would probably use in other languages) is to use a class variable: ##my_array. But class variables in ruby are a little problematic, so the best solution would be to make use of class instance variables, like that:
class SomeClass
class << self
attr_accessor :my_array
end
#my_array=[]
def initialize(user, record)
end
#my_array.each do |element|
alias_method "#{element}?".to_sym, :awesome_method
end
def awesome_method
puts 'awesome'
end
end
The syntax is a little tricky, so, if you look that up and it still doesn't makes sense, try just reading about scopes and using a regular class variable with ##.
Edit:
Ok, so, after your edit, it became more clear what you are trying to accomplish. A full working example is like follows:
class SomeClass
class << self
attr_accessor :my_array
end
#my_array=[]
def awesome_method
puts 'awesome'
end
def self.build!
#my_array.each do |element|
self.define_method("#{element}?".to_sym){ awesome_method }
end
end
end
class ChildClass < SomeClass
#my_array = %w[test little_test]
self.build!
end
child_instance = ChildClass.new
child_instance.test?
>> awesome
child_instance.little_test?
>> awesome
So, I've made some tweaks on SomeClass:
It does not need an initialize method
I tried to use the inherited hook for this problem. It won't ever work, because this hook is called as soon as "ChildClass < SomeClass" is written, and this must be before you can define something like #my_array = %w[test little_test]. So, I have added a self.build! method that must be called in the child instances so that they build their methods from my_array. This is inevitable, but I think it is also good, because it makes more explicit in the subclasses that you are doing something interesting there.
I think you want "define_method", not "alias_method".
awesome_method in passed in a block, which is ruby's way of doing functional programming.
With that done, ChildClass inherits from SomeClass, and it's instances have the dynamically created methods 'test?' and 'little_test?'.
You need to change my_array to class level accessible, in my case class constant.
class SomeClass
DYNAMIC_METHOD_NAMES = %w(method_a method_b method_C).freeze
def initialize(user, record)
end
DYNAMIC_METHOD_NAMES.each do |element|
alias_method "#{element}?".to_sym, :awesome_method
end
def awesome_method
puts 'awesome'
end
end
I have module CurrencyExchange with following methods
CURRENCIES = %w(uah rub eur usd)
def available_currencies
CURRENCIES.join(' ').downcase.split.permutation(2)
end
and when i want to use available_currencies with
define_method
available_currencies.each do |(c1, c2)|
define_method(:"#{c1}_to_#{c2}") do |cr| ... end end
i have got an error
undefined local variable or method `available_currencies'
for CurrencyExchange:Module (NameError)
but when i use it like
CURRENCIES.join(' ').downcase.split.permutation(2).each do |(c1, c2)|
define_method(:"#{c1}_to_#{c2}") .... end end
it works fine
Why it happens?
I think you need to write def self.available_currencies
You try to create other method in the class and Ruby searches in the loop for a class method .available_currencies.
You have to change your class method .available_currencies into a instance method #available_currencies or create the methods in your initializer.
Method 1:
class MyClass
def self.available_currencies
# Your logic...
end
# Your logic...
end
Method 2:
class MyClass
def init
available_currencies.each do |c|
define_method(c) do
# Whatever you want to do ...
end
end
end
def available_currencies
# Your logic...
end
end
I would recommend you the first way since you maybe want to use the currencies in classes. I would recommend you the second way, if you want for example different currencies for different instances.
Happy coding :)
Sorry if this is too simple. I'm looking for a way to make my ruby code dry : I want to call a number of methods on the same instance variable #var = Model.new(param) :
#var.method1
#var.method2
#var.method3
...
Is it possible to use the send method to write one line of code ? Btw, is it possible to call a block on Model.new to produce some more concise code ?
I believe that DRY should be used to make your code more maintainable, and more readable. I don't think it should be used to shorten the number of characters you type, or show-off your code acrobatics.
Both #Arup's and #p11y's solutions are great, within a context, but as a general rule (before knowing anything about your class or methods), I believe that writing
#var.method1
#var.method2
#var.method3
is more readable and maintainable than writing either
%i[method1 method2 method3].each(&#var.method(:send))
(you need to be fluent in advanced ruby to understand this)
or
#var.method1
.method2
.method3
(again the vanishing act is more confusing to the future reader than helpful)
Always think about who will read your code in 6 months, and what will be the clearest way for him to understand what's happening.
If you build method1, method2, etc. such that they return the instance itself using self, you can build a chainable interface. For example:
class Foo
def method1
# do something
self
end
def method2
# do something
self
end
def method3
# do something
self
end
# more methods...
end
#var = Foo.new
#var.method1.method2.method3
# or if this gets too long
#var.method1
.method2
.method3
Do as below :
%i[method1 method2 method3].each { |m| #var.send(m) }
If you want to make it more short,use :
%i[method1 method2 method3].each(&#var.method(:send))
When I wrote my original answer, I missed the last sentence in your question:
Btw, is it possible to call a block on Model.new to produce some more concise code ?
And the answer to this question is YES. This pattern is a builder pattern, which is implemented in several gems in ruby (such as tire).
The pattern states that the initialize method receives a block, which is run in the context of the created object, using instance_eval. If the block receives a parameter, the instance object is passed to it instead of changing the block's scope:
class Model
def initialize(name, &block)
#name = name
block.arity < 1 ? instance_eval(&block) : block.call(self) if block_given?
end
def method1
# something
end
def method2
# something
end
def method3
# something
end
end
And its usage will be something either like this:
#var = Model.new('model') do
method1
method2
method3
end
or, alternatively:
#var = Model.new('model') do |m|
m.method1
m.method2
m.method3
end
I've been studing Rails for a not such a long time up to now .... so if there are feel free to correct me
I see that there are two ways of defining methods in rails
def method_name(param)
def self.method_name(param)
The difference (as i understand) is that 1 is mainly used in controllers while 2 is used in models... but occasionaly i bump into methods in models that're defined like 1.
Could you explain to me the main difference of thease two methods?
Number 1. This defines a instance method, that can be used in instances of the model.
Number 2. This defines a class method, and can only be used by the class itself.
Example:
class Lol
def instance_method
end
def self.class_method
end
end
l = Lol.new
l.instance_method #=> This will work
l.class_method #=> This will give you an error
Lol.class_method #=> This will work
The method self.method_name defines the method on the class. Basically within the class definition think of self as referring to the class that is being defined. So when you say def self.method_name you are defining the method on the class itself.
class Foo
def method_name(param)
puts "Instance: #{param}"
end
def self.method_name(param)
puts "Class: #{param}"
end
end
> Foo.new.method_name("bar")
Instance: bar
> Foo.method_name("bar")
Class: bar
Background here.
In the above link, the following example is given:
class << self
def by_author(author)
where(:author_id => author.id)
end
end
Aside from that syntax being foreign to a beginner like me — I had always thought class methods were defined with def self.my_class_method — where can I find documentation about class methods in Ruby on Rails?
As far as I know, class methods are always called on the class itself (MyClass.my_class_method), but if class methods in Rails are chainable, it seems as though something else must be going on here!
Edit:
I suppose I sort of cheated by making that comment about the syntax for class methods. I'm really asking how Rails makes a class method chainable — I understand how method chaining works, but not how Rails can allow you to chain class methods without actually returning the class object itself after each "link" in the chain.
Class methods in Ruby are really just members of the singleton class, and doing class << self involves opening the singleton class directly and adding to it, removing the need to declare it in each method definition.
This article on Ruby singletons does a good job explaining.
As far as class methods being chainable, that isn't something specific to class methods, the second method call is simply called on the object returned from the first. For example:
bar = foo.do_something.do_more
is equivalent to:
tmp = foo.do_something
bar = tmp.do_more
In Rails, this chainability is most often used for building SQL queries (e.g., with where or order, etc.). This is achieved because each of these methods returns an ActiveRecord Relation.
The reason
foo.scoped.my_foo_class_method
works is because of ActiveRecord::Relation#method_missing doing the following:
elsif #klass.respond_to?(method)
scoping { #klass.send(method, *args, &block) }
Which checks if the ActiveRecord class responds to the method called, and if so, calls that.
Having class << self is also another way to define your methods so that you do not have to call "def self.my_method" or "def MyClass.my_method" for every single method that you are defining as a class method. Instead of calling
def self.my_method1
end
def self.my_method2
end
class << self
def my_method1
end
def my_method2
end
end
Cheers!
The following two bits of code are equivalent.
Using self.method:
class Hello
def self.world
puts "Hello, World!"
end
end
Using class << self:
class Hello
class << self
def world
puts "Hello, World!"
end
end
end
The only difference is readability, as well as the ease in refactoring.
The class << self technique is often used when metaprogramming.
There is another thread that explains this. class << self vs self.method with Ruby: what's better?