I have a class called Note, which includes an instance variable called time_spent. I want to be able to do something like this:
current_user.notes.inject{|total_time_spent,note| total_time_spent + note.time_spent}
Is this possible by mixing in the Enumerable module? I know you are supposed to do add include Enumerable to the class and then define an each method, but should the each method be a class or instance method? What goes in the each method?
I'm using Ruby 1.9.2
It's easy, just include the Enumerable module and define an each instance method, which more often than not will just use some other class's each method. Here's a really simplified example:
class ATeam
include Enumerable
def initialize(*members)
#members = members
end
def each(&block)
#members.each do |member|
block.call(member)
end
# or
# #members.each(&block)
end
end
ateam = ATeam.new("Face", "B.A. Barracus", "Murdoch", "Hannibal")
#use any Enumerable method from here on
p ateam.map(&:downcase)
For further info, I recommend the following article: Ruby Enumerable Magic: The Basics.
In the context of your question, if what you expose through an accessor already is a collection, you probably don't need to bother with including Enumerable.
The Enumerable documentations says the following:
The Enumerable mixin provides collection classes with several
traversal and searching methods, and with the ability to sort. The
class must provide a method each, which yields successive members of
the collection. If Enumerable#max, #min, or #sort is used, the objects
in the collection must also implement a meaningful <=> operator, as
these methods rely on an ordering between members of the collection.
This means implementing each on the collection. If you're interested in using #max, #min or #sort you should implement <=> on its members.
See: Enumerable
Related
I have a class QuestionList that stores a list of 'Question' objects.
class QuestionList
attr_accessor :questions
def initialize
#questions = []
end
end
I then add questions to the list and then "ask" these questions from my main class as so:
list = QuestionList.new
list.questions << Question.new(5, 3)
list.questions << Question.new(1, 5)
list.questions << Question.new(2, 4)
list.questions.each do |question|
puts "#{question.ask}"
end
where Question.ask simply outputs the question as a string.
I'm not sure how acceptable it is to be writing to an instance variable from my main class using the << operator, and list.questions.push(Question.new(5, 3)) is even more unclear from the main class.
Would it be better to have a QuestionsList.add_question(question) method?
The same goes for list.questions.each - is this acceptable to be used in the main class?
I think your use of attr_accessor here is fine, though depending on how much functionality you continue to add, it will likely be clearer to restrict functionality of that class to the class itself.
Regarding your question on using a method within QuestionList, this would come down to readability. Something to note first, however: you used QuestionsList.add_question(question) as an example. This would create a class method. What you really want here is an instance method, which would read as list.add_question(question), since you already have an instance of the list created. This blog post has some good information on the difference between class and instance methods.
I personally find instance methods would most clearly communicate your intent. I would write out QuestionList as follows:
class QuestionList
def initialize
#questions = []
end
def add_question(question)
#questions << question
end
def print_all_questions_in_list
#questions.each do |question|
puts "#{question.ask}"
end
end
end
This SO post has some excellent information on Ruby's attr methods, if you'd like additional info there.
The #questions array is a private internal implementation detail of your class. It should never ever get exposed to clients. There are many reasons for this, two examples are:
You overpromise an interface: now, all your clients depend on it being an array. What if you later want to change it to something else? A textfile? A database? A webservice?
You expose operations that break your object invariants: a client can, for example, add an integer to that array. Or nil. Or anything else that is not a Question.
How you store your questions should be an implementation detail. The QuestionList should have methods to manage the list of questions. It should probably have an each method (and include Enumerable), and an add method (possibly aliased to <<). Maybe also an [], if that makes sense. These methods could simply be delegated to the array, if convenient, but the point is: if you later decide to not use an array, you can do that without anyone even noticing. You can decide to only support those methods you actually want to support, as opposed to all ~100 methods of Array.
I am new to Ruby and I saw methods defined like:
def method_one
puts "method 1"
end
class MyClass
method_one
def method_two
puts "method 2"
end
end
The way method_one is used reminds me of Python decorators.The output of
c = MyClass.new
c.method_two
is
method 1
method 2
I have been trying to search for more information about this syntax/language feature in the Ruby documentation on the web but I don't know what keywords to search for.
What this is thing called?
TL;DR
This code doesn't do what you think it does. Don't do stuff like this.
Ruby's Top-Level Object
Ruby lets you define methods outside a class. These methods exist on a top-level object, which you can (generally) treat as a sort of catch-all namespace. You can see various posts like What is the Ruby Top-Level? for more details, but you shouldn't really need to care.
In your original post, method_one is just a method defined in the top-level. It is therefore available to classes and methods nested within the top-level, such as MyClass.
Methods in Classes
Despite what you think, the following doesn't actually declare a :method_one class or instance method on MyClass:
class MyClass
method_one
def method_two; end
end
Instead, Ruby calls the top-level ::method_one during the definition of the class, but it never becomes a class method (e.g. MyClass::method_one) or an instance method (e.g. MyClass.new.method_one). There might be a few use cases for doing this (e.g. printing debugging information, test injection, etc.) but it's confusing, error-prone, and generally to be avoided unless you have a really strong use case for it.
Better Options
In general, when you see something like this outside an academic lesson, the programmer probably meant to do one of the following:
Extend a class.
Add a singleton method to a class.
Include a module in a class.
Set up a closure during class definition.
The last gets into murky areas of metaprogramming, at which point you should probably be looking at updating your class initializer, or passing Proc or lambda objects around instead. Ruby lets you do all sorts of weird and wonderful things, but that doesn't mean you should.
I think you're a little mislead; the output of:
c = MyClass.new
c.method_two
is
#<MyClass:0x007feda41acf18>
"method 2"
You're not going to see method one until the class is loaded or if you're in IRB you enter the last end statement.
I would suggest looking into ruby's initialize method.
As far as I understand the Array class already mixes in the Enumerable module.
If that's so, why isn't there [:example].next?
Why do I need to make it [:example].to_enum.next?
to_enum has nothing to do with Enumerable, it returns an Enumerator. Array doesn't have a next method because next is an Enumerator method, not an Enumerable method.
Because the Enumerable module is different from the Enumerator class.
Being "Enumerable" means that the class gets a bunch of freebie methods that create "Enumerators". Compare to Java's Iterable and Iterator interfaces.
Here is a code sample from the ruby pickaxe book:
Class VowelFinder
include Enumerable
def initialize(string)
#string = string
end
def each
#string.scan(/[aeiou]/] do |vowel|
yield vowel
end
end
end
vf = VowelFinder.new("the quick brown fox jumped")
vf.inject(:+) # => 'euiooue'
What I am having a hard time understanding is where the modified 'each' method comes into play? I assume inject is calling it at some point but don't understand why it's doing it, and how I could predict or emulate this behavior in my code.
Thanks!
the VowelFinder class implements the protocol that is mandatory for the Enumerable module that you can include to gain a lot of ruby iterator methods: http://apidock.com/ruby/Enumerable
The Enumerable mixin provides collection classes with several
traversal and searching methods, and with the ability to sort. The
class must provide a method each, which yields successive members of
the collection. If Enumerable#max, #min, or #sort is used, the objects
in the collection must also implement a meaningful <=> operator, as
these methods rely on an ordering between members of the collection.
The call to inject actually causes a call to each. The way inject works is by going over all the elements of the Enumerable using each, applying the passed operator to the memo and to the next value and storing the result back into memo. The result of the entire call is the value of memo in the end. You can see the documentation in here.
You are correct that inject actually calls each method and the reason this happens is because inject actually uses each method internally. In fact, a lot if the Enumerable methods use the .each method; like #map, #select, #reject.
The reason for this is that .each is the actual method which allows looping in an Enumerable Object. The other methods are just so that things get easy for us, developers, and we don't have to use .each everywhere. Imagine having to write the above code using .each. It wouldn't be tough but vf.inject(:+) is definitely easier. So is the case with collect or map.
And the best way to implement this(as is done in Ruby) without repeating code is to have the other method call #each as there is no code duplication and each of #map or #collect or #inject does not have to traverse the Enumerable Object differently.
Genrally, I avoid using #each and there are so many other methods which makes our job easier. If you want to modify your array collection, it's advisable not to money-patch the #each method (unless, of course, you want all the other methods to change as well.)
Let's say I have a bunch of related functions that have no persistent state, say various operations in a string differencing package. I can either define them in a class or module (using self) and they can be accessed the exact same way:
class Diff
def self.diff ...
def self.patch ...
end
or
module Diff
def self.diff ...
def self.patch ...
end
I can then do Diff.patch(...). Which is 'better' (or 'correct')?
The main reason I need to group them up is namespace issues, common function names are all used elsewhere.
Edit: Changed example from matrix to diff. Matrix is a terrible example as it does have state and everyone started explaining why it's better to write them as methods rather than answer the actual question. :(
In your two examples, you are not actually defining methods in a Class or a Module; you are defining singleton methods on an object which happens to be a Class or a Module, but could be just about any object. Here's an example with a String:
Diff = "Use me to access really cool methods"
def Diff.patch
# ...
end
You can do any of these and that will work, but the best way to group related methods is in a Module as normal instance methods (i.e. without self.):
module Diff
extend self # This makes the instance methods available to the Diff module itself
def diff ... # no self.
def patch ...
end
Now you can:
use this functionality from within any Class (with include Diff) or from any object (with extend Diff)
an example of this use is the extend self line which makes it possible to call Diff.patch.
even use these methods in the global namespace
For example, in irb:
class Foo
include Diff
end
Foo.new.patch # => calls the patch method
Diff.patch # => also calls Diff.patch
include Diff # => now you can call methods directly:
patch # => also calls the patch method
Note: the extend self will "modify" the Diff module object itself but it won't have any effect on inclusions of the module. Same thing happens for a def self.foo, the foo won't be available to any class including it. In short, only instance methods of Diff are imported with an include (or an extend), not the singleton methods. Only subclassing a class will provide inheritance of both instance and singleton methods.
When you actually want the inclusion of a module to provide both instance methods and singleton methods, it's not completely easy. You have to use the self.included hook:
module Foo
def some_instance_method; end
module ClassMethods
def some_singleton_method; end
end
def self.included(base)
base.send :extend, ClassMethods
end
def self.will_not_be_included_in_any_way; end
end
class Bar
include Foo
end
# Bar has now instance methods:
Bar.new.some_instance_method # => nil
# and singleton methods:
Bar.some_singleton_method # => nil
The main difference between modules and classes is that you can not instantiate a module; you can't do obj = MyModule.new. The assumption of your question is that you don't want to instantiate anything, so I recommend just using a module.
Still you should reconsider your approach: rather than using arrays of arrays or whatever you are doing to represent a Matrix, it would be more elegant to make your own class to represent a matrix, or find a good class that someone else has already written.
Ruby Modules are used to specify behaviour, pieces of related functionality.
Ruby Classes are used to specify both state and behaviour, a singular entity.
There is a maxim in software design that says that code is a liability, so use the less code possible. In the case of Ruby, the difference in code lines is cero. So you can use either way (if you don't need to save state)
If you want to be a purist, then use a Module, since you won't be using the State functionality. But I wouldn't say that using a class is wrong.
As a trivia info: In Ruby a Class is a kind of Module.
http://www.ruby-doc.org/core-1.9.3/Class.html
The following also works
Matrix = Object.new
def Matrix.add ...
def Matrix.equals ...
That's because so-called "class methods" are just methods added to a single object, and it doesn't really matter what that object class is.
As a matter of form, the Module is more correct. You can still create instances of the class, even if it has only class methods. You can think of a module here as a static class of C# or Java. Classes also always have the instance related methods (new, allocate, etc.). Use the Module. Class methods usually have something to do with objects (creating them, manipulating them).