May one `inspect` without getting the context? - ruby

I thought inspect dumps the contents of an object, but I got far more than I understood the object to contain. I was dumping within a do ... end block. Is there another method similar to inspect that gives only what the object contains, or, how might one inspect with no context?

inspect is supposed to print a human-readable representation of the object. It is often used in trace statements. By default, it will print the object's class, object ID and instance variables associated with their values. So, it allows you to quickly determine the type, identity and attributes of the object.
Consider also the to_s method, which is supposed to convert the object to a string; it will often compose a new string representation using the object's attributes only; it may or may not use all of them.
Both of these methods do not take anything but its receiver into account.

Object#inspect is not a way to dump the contents of an object, it is merely a string representation of the object, meant to be human readable.
Individual classes or objects may overwrite the behavior of this method to return any string they want. The default behavior is to display the class name, object id, and any instance variables (which are converted to string by calling #inspect on each one). This level of recursion, where instance variables are also #inspected may be why you are seeing more "context" than you are expecting.
If you are looking for a way to dump the contents of an object to a string, so that it can be re-created from that string, you should look at Marshal. str = Marshal.dump(obj) attempts to dump the contents of an object to a string, while obj = Marshal.load(str) converts the string back into an object.
Another option, depending on the types of objects, is to serialize them using JSON or YAML.

As stated in the other answers, inspect is meant for debugging by dumping all content of the object (human-readable representation of obj).
I think you might find to_yaml more useful in your case:
object.to_yaml
# #=> --- !ruby/object:ObjectType
# attr1 => value
# attr2 => value
# ... etc
Tip:
I also found adding puts before to_yaml gives a more readable console output:
puts object.to_yaml

Related

Collections in Ruby - is there a collections class like Set but with the member access of Hash?

After reading the Collections chapter in Peter Jones' book, Effective Ruby, the Set class may seem to provide an interesting alternative to Hash. Concerning the Set class, Jones relates:
It’s a lot like its mathematical cousin, a collection of unordered unique elements with operations such as union, intersection, and subset/superset testing.
My only concern is in whether the Set class may not provide direct access to actual member objects.
Presently, I'm trying to use Set (or something like Set) to implement a naive OptionSet API, such that an option in the OptionSet may be of a type Option or ValueOption, with the latter being a subclass of Option. This API may need access to the objects stored in what respective collection for each OptionSet - whether stored in a separate Hash, Array, some other container object, or stored in the OptionSet via some inherited implementation e.g with Set as a superclass.
I'd like to use Set within OptionSet, or to simply implement OptionSet as a subclass of Set. However, if Set may not provide direct access to the member objects, once stored - short of iterating across every member object in the Set, as until finding any ostensible match (e.g. once finding any Option or ValueOption in the collection, such that the "match" would have an equivalent Option.name, typically a symbol) - maybe there's a more effective alternative?
I'd provide sample code, but the implementation of OptionSet is not presently usable. In pseudocode, I'm trying to implement OptionSet#getopt(name) as to return the value of any named Option object stored in the OptionSet, or false if no such option is stored.
The #getopt method would call self.getoptObj(name), a protected method such that would need to access the named option's actual Option object in the collection. Except for that part of the implementation, otherwise Set might be directly suitable.
In any analogy to Scheme-like languages, the Ruby standard library might not provide an AssociativeList class, per se? Simply, I wonder if there's any class like Set -- i.e with set-theoretic methods as in Set -- but with the member access of Hash?
Update
I've tried to implement a MappedSet class, at least in pseudocode, such as to use an instance Hash value to store a mapping between general "Keys" and member objects. I believe that would be redundant to the international storage of Set, however. Maybe I should simply extend Hash.
If you want to create a hash like class you can use DelegateClass:
class FalsyHash < DelegateClass(Hash)
def initialize(hash)
super.tap { |result| result.default = false }
end
end
irb(main):001:0> f = FalsyHash.new(a: :b)
=> {:a=>:b}
irb(main):002:0> f[:b]
=> false
irb(main):003:0> f.is_a?(Hash)
=> false
This is basically just a class that takes an instance of the provided class and wraps it so that method calls are forwarded. Since its not actually an instance of Hash we avoid the pitfalls that happen when core methods check if we are dealing with a hash which would occur if we used a subclass of Hash.
The same thing can be acheived with Delegator, SimpleDelegator and Forwardable - DelegateClass is just a straight forward way of wrapping classes.
You can also augment specific instances of Hash by extending them with a module:
module Reversable
def reverse
transform_values { |v| v.respond_to?(:reverse) ? v.reverse : v }
end
end
# Guess what this returns for a cookie
{ foo: 'olleH', bar: nil, baz: 'dlrow' }.extend(Reversable)
.reverse
.values
.compact
.sort
.join(" ")

Extract information about method receiver from stack

If we call caller method, we get something like:
prog.rb:3:in `a'
prog.rb:6:in `b'
prog.rb:9:in `c'
This is helpful for humans, but if I wanted to analyze the stack programmatically, not really, as two methods called :a may be entirely unrelated.
Is there any way/method to extract information about the receiver of the methods (like its class or object id) as well? For example:
prog.rb:3:in `Klass#a'
prog.rb:6:in `Modoole#b'
prog.rb:9:in `OtherKlass#c'
Formatting is only an example; this info might be an Array or anything.
I'm trying to emulate this with TracePoint, but forming a separate stack is a bad solution. Is there any Ruby way I missed in the docs?
There's an alternative to Kernel#caller named Kernel#caller_locations, that returns an array of Thread::Backtrace::Location objects. According to the manual, these should in theory be able to give you this information through the #label method.
Returns the label of this frame.
Usually consists of method, class, module, etc names with decoration.
After trying this out however, I need to question the term usually in the docs, because it seems to only return the method name still. Unless usually means it works for you, there seems to be no way of accomplishing this as of now.
Edit:
As per comment, one case that satisfies the condition of usually is when the method call is coming from within a Class or Module body:
class A
def trace
puts caller_locations.first.label
end
end
class B
A.new.trace
end
#=> <class:B>
module C
A.new.trace
end
#=> <module:C>

Accessing a string in a Ruby Object

I have a Ruby object #element that I used .inspect on. The result is below
#<Watir::Hidden:0x7b61410 located=false selector={:type=>"hidden", :tag_name=>"input", :id=>"foo"}>
How can I access "foo"
I've tried #element.id (which finds the ruby object id instead), #element[:id] and #element.selector[:id], #element['selector'][:id] etc.
Any help?
You can get attribute values using the attribute_value method:
#element.attribute_value("id")
Generally those are instance variables of an object. If they haven't exposed an attr_accessor, then you're touching private data, something that's generally frowned upon.
You can always get these if they are stored in an instance variable by using something like:
#element.instance_variable_get('#selector')[:id]
I wouldn't make use of this too extensively, it's a bad practice, but sometimes you have to do what you have to do.

Ruby nested send

Say I have an object with a method that accesses an object:
def foo
#foo
end
I know I can use send to access that method:
obj.send("foo") # Returns #foo
Is there a straightforward way to do a recursive send to get a parameter on the #foo object, like:
obj.send("foo.bar") # Returns #foo.bar
You can use instance_eval:
obj.instance_eval("foo.bar")
You can even access the instance variable directly:
obj.instance_eval("#foo.bar")
While OP has already accepted an answer using instance_eval(string), I would strongly urge OP to avoid string forms of eval unless absolutely necessary. Eval invokes the ruby compiler -- it's expensive to compute and dangerous to use as it opens a vector for code injection attacks.
As stated there's no need for send at all:
obj.foo.bar
If indeed the names of foo and bar are coming from some non-static calculation, then
obj.send(foo_method).send(bar_method)
is simple and all one needs for this.
If the methods are coming in the form of a dotted string, one can use split and inject to chain the methods:
'foo.bar'.split('.').inject(obj, :send)
Clarifying in response to comments: String eval is one of the riskiest things one can do from a security perspective. If there's any way the string is constructed from user supplied input without incredibly diligent inspection and validation of that input, you should just consider your system owned.
send(method) where method is obtained from user input has risks too, but there's a more limited attack vector. Your user input can cause you to execute any 0-arghument method dispatchable through the receiver. Good practise here would be to always whitelist the methods before dispatching:
VALID_USER_METHODS = %w{foo bar baz}
def safe_send(method)
raise ArgumentError, "#{method} not allowed" unless VALID_USER_METHODS.include?(method.to_s)
send(method)
end
A bit late to the party, but I had to do something similar that had to combine both 'sending' and accessing data from a hash/array in a single call. Basically this allows you to do something like the following
value = obj.send_nested("data.foo['bar'].id")
and under the hood this will do something akin to
obj.send(data).send(foo)['bar'].send(id)
This also works with symbols in the attribute string
value = obj.send_nested('data.foo[:bar][0].id')
which will do something akin to
obj.send(data).send(foo)[:bar][0].send(id)
In the event that you want to use indifferent access you can add that as a parameter as well. E.g.
value = obj.send_nested('data.foo[:bar][0].id', with_indifferent_access: true)
Since it's a bit more involved, here is the link to the gist that you can use to add that method to the base Ruby Object. (It also includes the tests so that you can see how it works)

basic question difference between # in active record

I have a basic question that I can not understand yet from ruby. If in active record, I have "#food" , how does it differ with "food". I recogn it is an array, but aren"t the active record can be assumes as a list of datas (array?)
Thanks for the sharing
That has nothing to do with ActiveRecord. It is just plain Ruby syntax.
#foo denotes an instance variable. It is scoped to the instance of its class, and is different for every instance of the class. The contents are kept as long as the class instance is kept.
foo may denote a local variable, which is valid only in the current block scope. It goes out of scope as soon as the block exits, and the contents are discarded unless referenced elsewhere.
And the # notation has nothing to do with arrays or any other data type. In Ruby, variables don't have data types. #bar will readily accept a string, integer or array without complaint. And so will bar.
A #var means a variable with its scope in an instance of a model.
http://www.techotopia.com/index.php/Ruby_Variable_Scope#Ruby_Instance_Variables

Resources