I'm trying to implement a gem that is redis wrapper for other library i.e to store the ruby object in the redis.
all work well but what I want is when I do
[Class].all
It give object like this
[#<Peagon:0x007fba589de3a0 #name="a", #omg=false ,#payload="one",#handler="--- one\n...\n"> ,#<Peagon:0x007fba589de1a0 #name="b", #omg=true,#payload="two",#handler="--- two\n...\n">]
but instead I want it to be look like how active record present the object
[#<Peagon name: "a",omg: false ,handler: "--- one\n...\n"> ,#<Peagon name="b", omg: true,handler: "--- two\n...\n">]
The reason for this that I not interested in showing the user the #payload instance variable because that is something set by the other library
so basically like this happen
[My gem]
class Peagon
include SomeModule
attr_accessor :name,:omg,:handler
def initialize(options)
#name = options[:name]
#omg = options
self.payload_object = options[:payload_object]
end
end
Now the [Other Library] has this module in it
module SomeModule
def payload=(object)
#payload ||= object
self.handler = #payload.to_yaml
end
def payload
#payload ||= YAML.load(self.handler)
end
end
NOTE :
Overwriting the payload method from other library is not in my mind
Now is it possible to get what I meant above
Looks like you just want to adjust what irb, the Rails console, and friends will display for objects of your class. If so, they just call inspect:
inspect → string
Returns a string containing a human-readable representation of obj. By default, show the class name and the list of the instance variables and their values (by calling inspect on each of them). User defined classes should override this method to make better representation of obj.
So all you need to do is provide your own inspect implementation, something like:
def inspect
"#<#{class} name: #{#name.inspect} ...>"
end
Related
Im currently doing some online tutorials about the ruby programming langauge and I think the explanations/examples I have been given thus far are lacking. I have two examples Id like to show you before directly asking the question.
The first example is:
Traditional Getters/Setters;
class Pen
def initialize(ink_color)
#ink_color = ink_color # this is available because of '#'
end
# setter method
def ink_color=(ink_color)
#ink_color = ink_color
end
# getter method
def ink_color
#ink_color
end
end
And the second example is:
ShortCutt Getter/Setters;
class Lamp
attr_accessor :color, :is_on
def initialize(color, is_on)
#color, #is_on = color, false
end
end
Ok, So for the first example I think its pretty straight forward. I am 'initializing' an accessible variable throughout my entire Lamp class called "#ink_color". If I wanted to set "#ink_color" to red or blue I would simply call my 'Setter' method and pass 'red' or 'blue' to the parameter (ink_color) in my setter. Then If I wanted to access or 'Get/Getter' the color I have 'Set/setter' I would call my getter method and ask for 'ink_color'.
The second example makes sense to me as well; Instead of typing out what the getter and setter methods look like, ruby provides a 'shortcut' that essentially runs code to build the getter and setter for you.
But heres the question - How do I reverse engineer the 'shortcut' version? Lets say I was looking at my above shortcut example and wanted to do it the "traditional" way without a shortcut?
Would the reverse engineering of the "shortcut" look something like the below code(my attempt that doesn't seem right to me)....
My Attempt/Example
class Lamp
def initialize(color, is_on)
#color = color
#is_on = is_on
end
def color=(color)
#color = color
end
def is_on=(is_on)
#is_on = is_on
end
def color
#color
end
def is_on
#is_on
end
end
Is my attempt right/workable code? It just seems like im missing a piece conceptually when it comes to this getter/setter stuff.
Understanding attr_accesor, attr_reader and attr_writer
These are Ruby's getters and setters shortcut. It works like C# properties, that injects the get_Prop (getter) and set_Prop (setter) methods.
attr_accessor: injects prop (getter) and prop= (setter) methods.
attr_reader: it's a shortcut for read-only properties. Injects prop method. The prop value can only be changed inside the class, manipulating the instance variable #prop.
attr_writer: it's a shortcut for write-only properties. Injects prop= method.
Ruby doesn't have methods called get_prop (getter) and set_prop (setter), instead, they're called prop (getter) and prop= (setter).
That being said, you can infer that
class Person
attr_accessor :name, :age
end
is the short version for
class Person
# getter
def name
return #name
end
# setter
def name=(value)
#name = value
end
end
You don't need to call return, Ruby methods returns the last executed statement.
If you are using Ruby on Rails gem, you can build model objects using new and passing properties values as arguments, just like:
p = Person.new(name: 'Vinicius', age: 18)
p.name
=> 'Vinicius'
That's possible because Rails injects something like this initialize method to ActiveRecord::Base and classes that includes ActiveModel::Model:
def initialize(params)
params.each do |key, value|
instance_variable_set("##{key}", value)
end
end
I make an API call:
def set_youtube(user)
Youtube.get_subscribers(user)
Youtube.get_views(user)
end
Here's my service object:
class Youtube
class << self
def get_hash(user)
## code to return a youtube JSON hash containing subscribers and views
end
def get_subscribers(user)
youtube_hash = Youtube.get_hash(user)
## code to return a subscriber count
end
def get_views(user)
youtube_hash = Youtube.get_hash(user)
## code to return a view count
end
end
end
However, I find it more elegant to call the method directly on the user. I don't want to make two calls to the API to get subscribers and then get views. But I also don't want to do:
youtube_hash = Youtube.get_hash(user)
Youtube.get_subscribers(youtube_hash)
Youtube.get_views(youtube_hash)
I want to temporarily cache the variable in the instance of this object so that I can use it for both class methods. What's the correct way to handle this?
You could use class variables (prefixed with ## symbols) and cache the hash, however you will then have to maintain that and it could get messy, instead I suggest using a more OO approach?
You could make it an instance of "Youtube", and cache the hash
class Youtube
def initialize(user)
#user = user
end
def hash
#hash ||= ... #the logic used to get the user hash in your get_hash using the #user instance variable
end
def subscribers
#subscribers ||= ... #the logic used to get the user subscribers in your get_subscribers however using the hash getter method which in turn uses the #hash instance variable
end
def views
#views ||= ... #the logic used to get the user views in your get_views however using the hash getter method which in turn uses the #hash instance variable
end
end
Then you can do the following and it will use the cached hash:
yt = Youtube.new(user: user)
yt.views
yt.subscribers
Maybe "YoutubeUser" is a better name? Just a suggestion. This all also could be moved to the User model and just use the Youtube service object. For example:
class User
before_create :set_youtube
def set_youtube
youtube = Youtube.new(self)
self.youtube_subscribers = youtube.subscribers
self.youtube_views = youtube.views
end
end
I assume set_youtube is an instance method, therefore no need to pass the user, however the class method would be similar as well.
I'm learning Ruby and made a class to help:
class WhatImDoing
def initialize
puts "not doing anything"
end
end
with the output of:
not doing anything
#<WhatImDoing:0xb74b14e8>
I'm curious, what is the second line all about? Is it a reference location for the WhatImDoing object I created? Can I access objects through this location(like a pointer or something)? Etc... Just trying to get a better understanding of Ruby, in general.
Thanks.
The second line is the output of irb, showing the return value of the last statement.
If you set something equal to that value:
> class WhatImDoing
def initialize
puts "not doing anything"
end
def ohai
puts "Ohai"
end
end
> tmp = WhatImDoing.new
=> #<WhatImDoing:0x5cd5a2a9>
You could use it:
> tmp.ohai
Ohai
If you had a custom to_s it would show that instead:
> class WhatImDoing
def to_s
"#{super} kthxbai"
end
endt
> tmp = WhatImDoing.new
=> #<WhatImDoing:0x3e389405> kthxbai
I'm assuming that was the output of irb. Irb tried to print your object, i.e. convert it to a string. Since you didn't provide a custom to_s ("to string") method, your object inherited this one:
http://ruby-doc.org/core-1.9.3/Object.html#method-i-to_s
Returns a string representing obj. The default to_s prints the object’s class and an encoding of the object id. As a special case, the top-level object that is the initial execution context of Ruby programs returns “main.”
Further digging into the source code reveals that the hexadecimal number is, indeed, the memory address occupied by that object instance. There isn't really anything fancy you can do with that information, in Ruby. It's just a convenient way to generate an unique identifier for an object instance.
Yes, it is reference to the object you are creating. Yes, you can access that object.
I am writing a class in Ruby where I have instance variables (i.e. #person_summary_info, #name, #dob, #favorite_food) for the class.
To parse a piece of text, I have a public method that I call from outside the class (let's call it interpret).
This method calls some private class methods such as get_name that use #person_summary_info to extract the respective piece of information (in this case, the name of the person). Should those private methods:
a) use the instance #person_summary_info, or get that information through a parameter passed to them (i.e. get_name vs get_name(person_summary_info))
b) modify the instance variable directly and return nothing, or modify nothing outside the scope of the function, and return the result (i.e. inside get_name, set #name = 'John', or return 'John')?
What is the best practice here?
Thanks!
I have included my best representation of your question in code at the bottom of my answer, but I'd like to present my solution as I understand your dilemma first...
Do this if your name attribute is meant to be publicly accessible:
class Person
attr_accessor :name
def initialize(name)
#name = name
end
def interpret(text_to_parse)
# I have no idea what you are parsing in real life
self.name = text_to_parse.split.last
end
end
person = Person.new("Frederick")
puts person.name
# => "Frederick"
person.interpret("Please, call me Fred")
puts person.name
# => "Fred"
Do this if your name attribute should not be (easily) publicly accessible: (For what it's worth, pretty much anything can be accessed one way or another in Ruby. One of the many things that make it awesome!)
class Person
def initialize(name)
#name = name
end
def interpret(text_to_parse)
# I have no idea what you are parsing in real life
#name = text_to_parse.split.last
end
end
person = Person.new("Frederick")
puts person.instance_variable_get("#name")
# => "Frederick"
person.interpret("Please, call me Fred")
puts person.instance_variable_get("#name")
# => "Fred"
And, as mentioned above, here's my best translation of your question into code:
class Person
def initialize
#person_summary_info = { name: "foo" }
#name = "bar"
#dob = "baz"
#favorite_food = "beer"
end
def interpret(text_to_parse)
# Some kind of parsing?
get_name_1
# OR
get_name_2(#person_summary_info)
# OR
get_name_3
# OR
#name = get_name_4
end
private
def get_name_1
#person_summary_info[:name]
end
def get_name_2(person_summary_info)
person_summary_info[:name]
end
def get_name_3
#name = 'John'
end
def get_name_4
'John'
end
end
Hopefully, you can see why there's some confusion in the comments about what you are asking exactly. If nothing else, maybe seeing this will help you to form your question more clearly so we can help!
Finally, you should avoid writing your own getters/setters in Ruby unless you need to hook in some custom code to the getting/setting processes -- use the class-level attr_reader/attr_writer/attr_accessor macros to create them for you.
If interpret() is not meant to change the state of a particular instance of Person, then consider naming the method something like get_name_from_string(string) and possibly making it static, since it doesnt do anything to the state of the instance.
If you want interpret() to change the state of a particular instance of Person, then consider changing the name of the method, prefixing it with set and include the attribute name being set (set_name_from_string()). If several attributes are being set, then perhaps set_from_string() and include a code comment stating what instance variables are being modified. Internally the method could call get/set_name() as described below.
Typically, getter/setter methods are public and should be quite simple, doing what their name suggests:
- getName() returns the instance variable #name
- setName(name) sets or overwrites the instance variable #name with the value passed in and returns nothing
In Java, this is a type of POJO, specifically Java Beans (excluding the part about needing to be serializable) Its very common programming practice in several different languages to have public setter/getter methods for the instance variables and to also have a default constructor (one that takes no arguments) and another constructor allowing you to set the instance variables upon instantiation of the Object.
using #instance directly from another class is a good way how to get into troubles. Each class should have it's own variables and anything you would like to process or return back should be assigned/returned directly.. that means that way
#instance = my_class.get_name(person_summary_info)
and not
my_class.get_name
Just try to imagine how to test that code using #instance variables and chance to reuse that piece of code..
just my 2c
I'm wondering if there's a way to return an object instead of a string when calling an object without any methods.
For instance:
class Foo
def initialize
#bar = Bar.new
end
end
Is there any way to define the Foo class so that the following happens:
foo = Foo.new
foo #returns #bar
In the specific case I'm interested in I'm using a presenter in a Rails view. The presenter sets up one main object and then loads a bunch of related content. The important part looks like this:
class ExamplePresenter
def initialize( id )
#example = Example.find( id )
end
def example
#example
end
...
end
If I want to return the example used by the ExamplePresenter I can call:
#presenter = ExamplePresenter.new(1)
#presenter.example
It would be nice if I could also return the example object by just calling:
#presenter
So, is there a way to set a default method to return when an object is called, like to_s but returning an object instead of a string?
If I understand correctly, you want to return the instance of Example when you call the ExamplePresenter instance. Such a direct mechanism does not exist in any language, and even if it did, it would block all access to the ExamplePresenter instance and its methods. So it is not logical.
There is something you can do however. You can make the ExamplePresenter class delegate methods to the Example instance inside it. Effectively you do not get a real Example from #presenter but you get an ExamplePresenter that passes all eligible methods into its internal Example effectively acting in behalf of it.
Some ways of doing this is:
method_missing
class ExamplePresenter
… # as defined in the question
def method_missing symbol, *args
if #example.respond_to?(symbol)
#example.send(symbol, *args)
else
super
end
end
end
This will pass any method call down to the internal Example if the ExamplePresenter cannot respond to it. Be careful, you may expose more than you want of the internal Example this way, and any method already defined on ExamplePresenter cannot be passed along.
You can use additional logic inside method_missing to limit exposure or pre/post process the arguments/return values.
Wrapper methods
You can define wrapper methods on ExamplePresenter that do nothing but pass everything to the internal Example. This gives you explicit control on how much of it you want to expose.
class ExamplePresenter
… # as before
def a_method
#example.a_method
end
def another_method(argument, another_argument)
#example.another_method(argument, another_argument)
end
end
This gets tedious fast, but you can also add logic to alter arguments before passing it along to the Example or post process the results.
You can also mix and match the above two methods
Delegator library
There is a library in Ruby stdlib called Delegator built exactly for this purpose. You may look into it.
Although this is not recommended, you can do:
class Foo
def self.new
#bar = Bar.new
end
end
If you actually do need to create an instance of Foo, then
class << Foo
alias original_new :new
end
class Foo
def self.new
self.original_new # It will not be useful unless you assign this to some variable.
#bar = Bar.new
end
end