Is there a practical application to the "crazy-ness" below?
It seems like this is a way for ted to always be able to return himself to the world and people will think they are talking to ted who they expect to act a certain way and be a certain age... but he isn't acting the way he portrays himself and is lying about his age to someone.
What 'trickery' is possible when an object is returned and you check on what that object represents and is capable of... but really that object was acting another way and capable of other things before returning.
class Person
def age
21
end
def who_am_i?
puts "I am #{self} / #{object_id} and I am #{age} years old"
self
end
end
ted = Person.new
def ted.singleton_who_am_i?
class << self
def age
0
end
end
puts "I am #{self} / #{object_id} and I am #{age} years old"
self
end
puts ted.who_am_i? == ted.singleton_who_am_i?
>> I am #<Person:0x100138340> / 2148123040 and I am 21 years old
>> I am #<Person:0x100138340> / 2148123040 and I am 0 years old
>> true
http://andrzejonsoftware.blogspot.ca/2011/02/dci-and-rails.html
in DCI, your data model gets different type of behavior based on the context it is used it. Usually it is done with object.extend, but it is pretty much what you are doing above -- taking advantage of the metaclass.
Another example (and probably why things work that way) is the way classes work in ruby. If you say
class Foo
end
that is the same thing as saying
Foo = Class.new
end
meaning that what you are doing is assigning a new instance of class Class to a constant. When you define a method on that class, you don't want it applied to all instance of class Class, you only want it on the class you are defining. So when you say
class Foo
def self.bar
end
end
it is the exact thing as saying
class Foo
end
def Foo.bar
end
which is exactly the same principal as you are talking about in your question
(sorry if that was unclear)
Ruby is a very dynamic language letting you inject code into objects at runtime. There are some good uses for it but it can also make code very hard to debug and understand.
It's totally counter-intuitive for a method that queries an object to modify that object. Nobody would expect a call to who_am_i to modify the object.
On the other hand replacing methods like that can make unit testing classes really straight forward.
If you want to test how the class behaves with different ages you can inject code like that before your tests.
Related
I have recently learned how to create classes, although I am not ENTIRELY sure where and why I should use them.
I'd use them to create objects, which have similar methods/properties.
I tried making a gag code, but I stumbled upon a question I can't find an answer to.
class Person
def initialize(name,health)
#name = name
#hp = health
end
def kick
#hp -= 1
if (#hp <= 0)
puts "#{#name} got REKT!"
end
end
end
#Friends
michael = Person.new("Michael", 10)
10.times { michael.kick }
Even though this code works, I'm wondering if it is possible to use/call mihchael's hp outside the class? Perhaps sort of like a hash? michael[#hp]? But this doesn't work, even if i set hp to be a global variable.
Should all if/else statements who check object's properties be inside the class?
Thank you very much
The standard way to do this in Ruby is to create an accessor:
class Person
attr_reader :name
attr_reader :hp
end
Then outside the class you can call things like:
puts "#{michael.name} has only #{michael.hp} HP left"
The reason you create objects is to organize your code and data into logical contexts and containers.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
Abstract class looks in Ruby code like an alien from remote planet Java. I'm trying to collect Ruby tricks which can substitute this unwanted pattern.
Let's take a completely random example:
class AbstractRace < Struct.new(:runner_count)
def go!
runner_count.times.map do |index|
Thread.new do
run(index)
end
end.each(&:join)
end
def run(index)
raise 'To be implemented in derivative classes'
end
end
class RunnerRace < AbstractRace
def run(index)
puts "I am runner number #{index}. I am running"
end
end
class CarRace < AbstractRace
def run(index)
puts "I am car number #{index}. I am accelerating"
end
end
RunnerRace.new(2).go!
CarRace.new(2).go!
How to rewrite it? A possible approach would be using a mixin, like this:
require 'active_support/concern'
module Race
extend ActiveSupport::Concern
def go!
participant_count.times.map do |index|
Thread.new do
run(index)
end
end.each(&:join)
end
module ClassMethods
def configure_race(methods)
[:participant_count, :run].each do |method_symbol|
define_method method_symbol, methods[method_symbol]
end
end
end
end
class RunnerRace < Struct.new(:runner_count)
include Race
configure_race participant_count: ->() { runner_count },
run: ->(index) { puts "I am runner number #{index}. I am running" }
end
class CarRace < Struct.new(:car_count)
include Race
configure_race participant_count: -> { car_count },
run: ->(index) { puts "I am car number #{index}. I am going" }
end
RunnerRace.new(2).go!
CarRace.new(2).go!
What other solutions could be? Is there a common idiom for such case?
Why not just take advantage of the fact that Ruby is a dynamic language?
class Race
attr_reader :participants
def initialize(participants)
#participants = participants
end
def go!
participants.each_with_index.map do |index,participant|
Thread.new do
participant.run(index)
end
end.each(&:join)
end
end
class CarEntry
def run(index)
puts "I am car number #{index}. I am going"
end
end
There is no need for anything running in a 'race' to extend a superclass. All anything in the race must do is be capable of racing i.e having a
run(index)
method that does something.
In ruby I would tend to think of 'AbstractRace' as more of a role for a class to play. Roles are best encapsulated in modules (as you've suggested in your first response).
If you are trying to come up with a general ruby solution, however, I would recommend removing the reference to ActiveSupport::Concern. This module is something that comes from Rails and may not be available in all ruby environments.
There is nothing wrong with what you have written there and I'm not entirely sure what you are unhappy with.
That being said, this is Ruby and there is no need to define the run method on your AbstractRace class. If that's what is bothering you, then just don't do it.
The reason you put it there is to show both yourself and other developers who might be working on the code that a Race should have a run method. It's defining the interface. It definitely is not required though, but it is the "proper" way to make an object oriented class hierarchy.
I think you're missing the point of abstract classes
Languages like Java use abstract classes because they want to:
Collect common code for derived classes in one place (common base class), and
Prevent instantiating this common base class, because it is a base class.
If you wanted to achieve the same goals, you could do this by:
Creating a base class with the common code
Giving it a private constructor:
```
class AbstractRace
private:
def initialize
end
end
```
The other reason people use abstract classes, is the same as interfaces: they want to guarantee that some method exists on a derived class.
Unfortunately, there's no such construction as Ruby; in fact, this is "un-Ruby-like." In Ruby, we rely on "duck typing," which means "if it quacks, it's a duck!" Observe:
class Car
def drive
return 'VROOOM!'
end
end
class Duck
def quack
return 'Quack quack!'
end
end
test_objs = [Car.new, Duck.new]
test_objects.each do |some_obj|
if some_obj.respond_to?(:quack)
puts "#{some_obj} is a duck! #{some_obj.quack}"
else
puts 'Not a duck, sorry.
end
end
This will output something like <Duck:0x123456> is a duck! Quack quack!
This is relying on "duck typing," by checking for the existence of methods before using them. This is the closest idiom in Ruby.
I need to make the following code functional by building a "Car" class. I feel I must be overlooking something simple. any help would be appreciated. The # indicates the expected output
# Make the following code functional by building a Car class
c = Car.new("blue")
puts c.color # blue
puts c.repaint_count # 0
c.paint("red")
c.paint("green")
puts c.repaint_count # 2
puts c.color # green
here is what I have done:
class Car
##repaint_count = 0
def initialize(color)
#color = color
end
def self.paint(color)
#color = color
##repaint_color += 1
end
def self.color
#color
end
end
I guess I am being thrown by the c.color / c.paint: should I be defining these methods and setting them equal to class or something else ? I think I am missing something about classes and inheritance.
I guess I am being thrown by the c.color / c.paint: should I be
defining these methods and setting them equal to class or something
else ? I think I am missing something about classes and inheritance.
I think in fact you are over-complicating it by worrying about these things at this stage. The question is not about inheritance. Although in some ways it is poorly specified in that it is possible to mis-interpret the question text and assign some properties to the class other than the instance.
So first things, you have got that the question expects you to implement a Car class, and that there is internal state to track for the current color and the number of times it has changed. You have partly mis-understood the repaint count and made it a class variable. It needs to be an instance variable - it is intended to be the number of times a specific car has been re-painted, not the number of times any car has been re-painted. Although the example numbers would be the same, the difference is that the question asks for c.repaint_count not Car.repaint_count, and c is an instance of Car, hence you want to store the count as an instance variable - set it to 0 in the constructor.
Similar confusion in your accessor code. Ruby's use of self is a little confusing - it changes meaning on context in the code. If you changed your def self.paint to just def paint and similarly for color then with the change from last paragraph, you are pretty much done.
One last thing, you need to implement repaint_count accessor similar to how you have done with color (and again, without the self. which would make it a class method)
You seem to be confusing classes and instances. c is an instance of Car, and is not the class Car itself. Unless you want to count the total repaint_count throughout the Car class, you should not use a class variable ##repaint_count, but should use an instance variable. Your paint method is a class method, and is not well defined. In addition the definition body looks like you randomly put something.
class Car
attr_reader :color, :repaint_count
def initialize color
#color = color
#repaint_count = 0
end
def paint color
#color = color
#repaint_count += 1
end
end
Well, this looks like a homework question, which I'm not going to write for you. However I'll give you some pointers.
You create/ open up a class like this.
class Foo
end
When you open up a class like this you can set it up to accept arguments immediately, like so:
class Foo
attr_accessor :bar, :bar_counter
def initialize(arg_1)
#bar = arg_1
#bar_counter = 0
end
# And add methods with any name like so.
def increase_bar
#bar_counter += 1
end
def change_bar(arg)
#bar = arg
end
end
This will explain the differences between attr_accessor, attr_reader, attr_writer https://stackoverflow.com/a/4371458/2167965
People have various opinions on Codecademy, but in my opinion it's perfect for teaching basic syntax like this. There's also Ruby Koans, and Ruby Test First.
My recommendations would be to start with codecademy to learn the syntax, and move to Test First to flesh out those concepts.
I'm trying to fill in class variables for a class instance from a file, and the only way I've managed to figure how to do this is something like
a=Thing.new
File.read("filename.ext").each_line do |arguments| #this will => things like #variable=str\n
eval( "a.instance_eval {" + arguments.chop + "}") #hence the awkward eval eval chop
end
The only problem I've found is that in trying to impliment this in a class method (to do this for several instances in a go), I don't know how to make this happen:
class Thing
attr_accessor :variable
def self.method
File.read("filename.ext").each_line do |arguments|
eval("instance.instance_eval{" + arguments.chop + "}") #this line
end
end
end
namely, the reference to the instance calling the method. self will just just be Thing in this case, so is there any way to do this? More pertinent might be a better way to go about this overall. I only just learned ruby last night, so I haven't had an opportunity to see some of the neater tricks that are to be had, and my language maturity is a little fresh yet as a result.
For context, Thing is a character in a game, loading its base values from a savefile.
Well, first off, take a look at Marshal. It's specifically used for dumping data structures to serialized formats and loading them back.
The said, if you want to persist in your direction, then try something like this:
class Thing
attr_accessor :variable
def self.method
File.read("filename.ext").each_line do |arguments|
ivar, val = arguments.strip.split("=", 2)
instance.instance_variable_set(ivar, val)
end
end
end
#instance_variable_set allows you to...well, set instance variables on an object by name. No ugly eval necessary!
By way of demonstration:
class Foo
attr_accessor :bar
end
foo = Foo.new
foo.instance_variable_set("#bar", "whatzits")
puts foo.bar # => whatzits
I'm trying to learn ruby by building a basic Campfire bot to screw around with at work. I've gotten pretty far (it works!) and learned a lot (it works!), but now I'm trying to make it a bit more complex by separating the actions to be performed out into their own classes, so that they can be easier to write / fix when broken. If you're interested in seeing all the (probably crappy) code, it's all up on GitHub. But for the sake of this question, I'll narrow the scope a bit.
Ideally, I would like to be able to create plugins easily, name them the same as the class name, and drop them into an "actions" directory in the root of the project, where they will be instantiated at runtime. I want the plugins themselves to be as simple as possible to write, so I want them all to inherit some basic methods and properties from an action class.
Here is action.rb as it currently exists:
module CampfireBot
class Action
#handlers = {}
def initialize(room)
#room = room
end
class << self
attr_reader :handlers
attr_reader :room
def hear(pattern, &action)
Action.handlers[pattern] = action
end
end
end
end
Where #room is the room object, and #handlers is a hash of patterns and blocks. I kind of don't understand why I have to do that class << self call, but that's the only way I could get the child plugin classes to see that hear method.
I then attempt to create a simple plugin like so (named Foo.rb):
class Foo < CampfireBot::Action
hear /foo/i do
#room.speak "bar"
end
end
I then have my plugins instantiated inside bot.rb like so:
def load_handlers(room)
actions = Dir.entries("#{BOT_ROOT}/actions").delete_if {|action| /^\./.match(action)}
action_classes = []
# load the source
actions.each do |action|
load "#{BOT_ROOT}/actions/#{action}"
action_classes.push(action.chomp(".rb"))
end
# and instantiate
action_classes.each do |action_class|
Kernel.const_get(action_class).new(room)
end
#handlers = Action.handlers
end
The blocks are then called inside room.rb when the pattern is matched by the following:
handlers.each do |pattern, action|
if pattern.match(msg)
action.call($~)
end
end
If I do puts #room inside the initialization of Action, I see the room object printed out in the console. And if I do puts "foo" inside Foo.rb's hear method, I see foo printed out on the console (so, the pattern match is working). But, I can't read that #room object from the parent class (it comes out as a nil object). So obviously I'm missing something about how this is supposed to be working.
Furthermore, if I do something to make the plugin a bit cleaner (for larger functions) and rewrite it like so:
class Foo < CampfireBot::Action
hear /foo/i do
say_bar
end
def say_bar
#room.speak "bar"
end
end
I get NoMethodError: undefined method 'say_bar' for Foo:Class.
The definition of hear can be pulled out of the class << self block and changed to:
def self.hear(pattern, &action)
Action.handlers[pattern] = action
end
to yield the exact same result. That also immediately explains the problem. hear Is a class method. say_bar is an instance method. You can't call an instance method from a class method, because there simply isn't an instance of the class available.
To understand the class << self bit, you'll have to do your own reading and experiments: I won't try to improve on what has already been said. I'll only say that within the class << self .. end block, self refers to the eigenclass or metaclass of the CampfireBot::Action class. This is the instance of the Class class that holds the definition of the CampfireBot::Action class.