> require 'ap'
> ap 1.methods
> ap 1.methods
[
[ 0] !() Integer (BasicObject)
[ 1] !=(arg1) Integer (BasicObject)
[ 2] !~(arg1) Integer (Kernel)
[ 3] %(arg1) Integer
[ 4] &(arg1) Integer
[ 5] *(arg1) Integer
[ 6] **(arg1) Integer
[ 7] +(arg1) Integer
[ 8] +@() Integer (Numeric)
[ 9] -(arg1) Integer
[ 10] -@() Integer
[ 11] /(arg1) Integer
[ 12] <(arg1) Integer
[ 13] <<(arg1) Integer
[ 14] <=(arg1) Integer
[ 15] <=>(arg1) Integer
[ 16] ==(arg1) Integer
[ 17] ===(arg1) Integer
[ 18] =~(arg1) Integer (Kernel)
[ 19] >(arg1) Integer
[ 20] >=(arg1) Integer
[ 21] >>(arg1) Integer
[ 22] [](arg1) Integer
[ 23] ^(arg1) Integer
[ 24] __id__() Integer (BasicObject)
[ 25] __send__(*arg1) Integer (BasicObject)
[ 26] abs() Integer
[ 27] abs2() Integer (Numeric)
[ 28] ai(*options) Integer (Kernel)
[ 29] allbits?(arg1) Integer
[ 30] amazing_print(object, *options) Integer (Kernel)
[ 31] angle() Integer (Numeric)
> ap 1.methods
[
[ 0] !() Integer (BasicObject)
[ 1] !=(arg1) Integer (BasicObject)
[ 2] !~(arg1) Integer (Kernel)
[ 3] %(arg1) Integer
[ 4] &(arg1) Integer
[ 5] *(arg1) Integer
[ 6] **(arg1) Integer
[ 7] +(arg1) Integer
[ 8] +@() Integer (Numeric)
[ 9] -(arg1) Integer
[ 10] -@() Integer
[ 11] /(arg1) Integer
[ 12] <(arg1) Integer
[ 13] <<(arg1) Integer
[ 14] <=(arg1) Integer
[ 15] <=>(arg1) Integer
[ 16] ==(arg1) Integer
[ 17] ===(arg1) Integer
[ 18] =~(arg1) Integer (Kernel)
[ 19] >(arg1) Integer
[ 20] >=(arg1) Integer
[ 21] >>(arg1) Integer
[ 22] [](arg1) Integer
[ 23] ^(arg1) Integer
[ 24] __id__() Integer (BasicObject)
[ 25] __send__(*arg1) Integer (BasicObject)
[ 26] abs() Integer
[ 27] abs2() Integer (Numeric)
[ 28] ai(*options) Integer (Kernel)
[ 29] allbits?(arg1) Integer
[ 30] amazing_print(object, *options) Integer (Kernel)
[ 31] angle() Integer (Numeric)
- arguments
- where they're defined.
1.methods
=> [:-@, :**, :<=>, :upto, :<<, :<=, :>=, :==, :chr, :===, :>>, :[], :%, :&, :inspect, :*, :+, :ord, :-, :/, :size, :succ, :<, :>, :to_int, :coerce, :to_s, :to_i, :to_f, :divmod, :to_r, :fdiv, :modulo, :remainder, :abs, :magnitude, :integer?, :floor, :ceil, :round, :truncate, :^, :odd?, :even?, :allbits?, :anybits?, :nobits?, :downto, :times, :pred, :pow, :bit_length, :digits, :numerator, :denominator, :rationalize, :gcd, :lcm, :gcdlcm, :next, :div, :|, :~, :imag, :abs2, :+@, :phase, :to_c, :polar, :angle, :conjugate, :conj, :eql?, :singleton_method_added, :i, :real?, :zero?, :nonzero?, :finite?, :infinite?, :step, :positive?, :negative?, :clone, :dup, :arg, :quo, :rectangular, :rect, :real, :imaginary, :between?, :clamp, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :instance_variable_set, :protected_methods, :instance_variables, :instance_variable_get, :private_methods, :public_methods, :public_send, :method, :public_method, :singleton_method, :define_singleton_method, :extend, :to_enum, :enum_for, :=~, :!~, :respond_to?, :freeze, :object_id, :send, :display, :nil?, :hash, :class, :singleton_class, :itself, :yield_self, :then, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :methods, :singleton_methods, :equal?, :!, :instance_exec, :!=, :instance_eval, :__id__, :__send__]
I'll refer to these as vanilla
1.methods.class
=> Array
1.methods.map(&:class)
1.methods.map(&:class)
=> [Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol, Symbol]
1.methods.map(&:class).uniq
=> [Symbol]
1.methods
1.hour.ago
1.methods
"".methods
User.first.methods
User.methods
1.method(:+).methods
➜ ap 1.methods.dup
➜ ap 1.methods.dup
[
[ 0] !() Integer (BasicObject)
[ 1] !=(arg1) Integer (BasicObject)
[ 2] !~(arg1) Integer (Kernel)
[ 3] %(arg1) Integer
[ 4] &(arg1) Integer
[ 5] *(arg1) Integer
[ 6] **(arg1) Integer
[ 7] +(arg1) Integer
[ 8] +@() Integer (Numeric)
[ 9] -(arg1) Integer
[ 10] -@() Integer
[ 11] /(arg1) Integer
[ 12] <(arg1) Integer
[ 13] <<(arg1) Integer
[ 14] <=(arg1) Integer
[ 15] <=>(arg1) Integer
[ 16] ==(arg1) Integer
[ 17] ===(arg1) Integer
[ 18] =~(arg1) Integer (Kernel)
[ 19] >(arg1) Integer
[ 20] >=(arg1) Integer
[ 21] >>(arg1) Integer
[ 22] [](arg1) Integer
[ 23] ^(arg1) Integer
[ 24] __id__() Integer (BasicObject)
[ 25] __send__(*arg1) Integer (BasicObject)
[ 26] abs() Integer
[ 27] abs2() Integer (Numeric)
[ 28] ai(*options) Integer (Kernel)
[ 29] allbits?(arg1) Integer
[ 30] amazing_print(object, *options) Integer (Kernel)
[ 31] angle() Integer (Numeric)
Can we get our less surprising vanilla output back?
methods = 1.methods
methods = 1.methods
ap methods
=> [...pretty...]
m = 1.methods
ap m.take(m.length)
m = 1.methods
ap m.take(m.length)
[
[ 0] :-@,
[ 1] :**,
[ 2] :<=>,
[ 3] :upto,
[ 4] :<<,
[ 5] :<=,
[ 6] :>=,
[ 7] :==,
[ 8] :chr,
[ 9] :===,
...
Something special about the return value of methods
Object.new.methods
=> [:__binding__, :pry, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :to_yaml, :pretty_print_instance_variables, :pretty_print_cycle, :pretty_print_inspect, :pretty_print, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :instance_variable_set, :instance_variables, :instance_variable_get, :public_send, :method, :public_method, :singleton_method, :define_singleton_method, :pretty_inspect, :extend, :awesome_print, :to_enum, :enum_for, :ai, :<=>, :===, :=~, :!~, :byebug, :eql?, :respond_to?, :remote_byebug, :debugger, :freeze, :inspect, :object_id, :send, :awesome_inspect, :amazing_print, :to_s, :display, :nil?, :hash, :class, :singleton_class, :clone, :dup, :itself, :yield_self, :then, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :equal?, :!, :==, :instance_exec, :!=, :instance_eval, :__id__, :__send__]
ap [:__binding__, :pry, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :to_yaml, :pretty_print_instance_variables, :pretty_print_cycle, :pretty_print_inspect, :pretty_print, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :instance_variable_set, :instance_variables, :instance_variable_get, :public_send, :method, :public_method, :singleton_method, :define_singleton_method, :pretty_inspect, :extend, :awesome_print, :to_enum, :enum_for, :ai, :<=>, :===, :=~, :!~, :byebug, :eql?, :respond_to?, :remote_byebug, :debugger, :freeze, :inspect, :object_id, :send, :awesome_inspect, :amazing_print, :to_s, :display, :nil?, :hash, :class, :singleton_class, :clone, :dup, :itself, :yield_self, :then, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :equal?, :!, :==, :instance_exec, :!=, :instance_eval, :__id__, :__send__]
[
[ 0] :binding,
[ 1] :pry
[ 2] :methods,
[ 3] :singleton_methods,
[ 4] :protected_methods,
[ 5] :public_methods,
...
Great! Vanilla
ap Object.new.methods
[pretty]
ap [:__binding__, :pry, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :to_yaml, :pretty_print_instance_variables, :pretty_print_cycle, :pretty_print_inspect, :pretty_print, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :instance_variable_set, :instance_variables, :instance_variable_get, :public_send, :method, :public_method, :singleton_method, :define_singleton_method, :pretty_inspect, :extend, :awesome_print, :to_enum, :enum_for, :ai, :<=>, :===, :=~, :!~, :byebug, :eql?, :respond_to?, :remote_byebug, :debugger, :freeze, :inspect, :object_id, :send, :awesome_inspect, :amazing_print, :to_s, :display, :nil?, :hash, :class, :singleton_class, :clone, :dup, :itself, :yield_self, :then, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :equal?, :!, :==, :instance_exec, :!=, :instance_eval, :__id__, :__send__]
[vanilla]
return value from methods gives us pretty output the equivalent plain list of symbols, prints out a list of symbols
> Object.new.methods.map(&:object_id)
=> [2078428, 1594268, 79388, 79708, 80028, 80348, 80668, 833308, 1940508, 1186268, 1942108, 824028, 82228, 82268, 82868, 83188, 83508, 83548, 81628, 80988, 81308, 177948, 424348, 424668, 424988, 426908, 1146588, 184988, 1592988, 448348, 448988, 1352668, 2668, 2788, 2828, 2848, 2751388, 3028, 3048, 2751708, 2752028, 53468, 53788, 54428, 59548, 1535388, 1536348, 64348, 321628, 74548, 74588, 74908, 75228, 75548, 75868, 76188, 76508, 76828, 77148, 77748, 77788, 78108, 78708, 78748, 79348, 72308, 668, 2768, 177628, 2808, 177308, 445148, 59868]
> [:__binding__, :pry, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :to_yaml, :pretty_print_instance_variables, :pretty_print_cycle, :pretty_print_inspect, :pretty_print, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :instance_variable_set, :instance_variables, :instance_variable_get, :public_send, :method, :public_method, :singleton_method, :define_singleton_method, :pretty_inspect, :extend, :awesome_print, :to_enum, :enum_for, :ai, :<=>, :===, :=~, :!~, :byebug, :eql?, :respond_to?, :remote_byebug, :debugger, :freeze, :inspect, :object_id, :send, :awesome_inspect, :amazing_print, :to_s, :display, :nil?, :hash, :class, :singleton_class, :clone, :dup, :itself, :yield_self, :then, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :equal?, :!, :==, :instance_exec, :!=, :instance_eval, :__id__, :__send__].
map(&:object_id)
=> [2078428, 1594268, 79388, 79708, 80028, 80348, 80668, 833308, 1940508, 1186268, 1942108, 824028, 82228, 82268, 82868, 83188, 83508, 83548, 81628, 80988, 81308, 177948, 424348, 424668, 424988, 426908, 1146588, 184988, 1592988, 448348, 448988, 1352668, 2668, 2788, 2828, 2848, 2751388, 3028, 3048, 2751708, 2752028, 53468, 53788, 54428, 59548, 1535388, 1536348, 64348, 321628, 74548, 74588, 74908, 75228, 75548, 75868, 76188, 76508, 76828, 77148, 77748, 77788, 78108, 78708, 78748, 79348, 72308, 668, 2768, 177628, 2808, 177308, 445148, 59868]
> Object.new.methods.map(&:object_id)
=> [2078428, 1594268, 79388, 79708, 80028, 80348, 80668, 833308, 1940508, 1186268, 1942108, 824028, 82228, 82268, 82868, 83188, 83508, 83548, 81628, 80988, 81308, 177948, 424348, 424668, 424988, 426908, 1146588, 184988, 1592988, 448348, 448988, 1352668, 2668, 2788, 2828, 2848, 2751388, 3028, 3048, 2751708, 2752028, 53468, 53788, 54428, 59548, 1535388, 1536348, 64348, 321628, 74548, 74588, 74908, 75228, 75548, 75868, 76188, 76508, 76828, 77148, 77748, 77788, 78108, 78708, 78748, 79348, 72308, 668, 2768, 177628, 2808, 177308, 445148, 59868]
> [:__binding__, :pry, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :to_yaml, :pretty_print_instance_variables, :pretty_print_cycle, :pretty_print_inspect, :pretty_print, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :instance_variable_set, :instance_variables, :instance_variable_get, :public_send, :method, :public_method, :singleton_method, :define_singleton_method, :pretty_inspect, :extend, :awesome_print, :to_enum, :enum_for, :ai, :<=>, :===, :=~, :!~, :byebug, :eql?, :respond_to?, :remote_byebug, :debugger, :freeze, :inspect, :object_id, :send, :awesome_inspect, :amazing_print, :to_s, :display, :nil?, :hash, :class, :singleton_class, :clone, :dup, :itself, :yield_self, :then, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :equal?, :!, :==, :instance_exec, :!=, :instance_eval, :__id__, :__send__].
map(&:object_id)
=> [2078428, 1594268, 79388, 79708, 80028, 80348, 80668, 833308, 1940508, 1186268, 1942108, 824028, 82228, 82268, 82868, 83188, 83508, 83548, 81628, 80988, 81308, 177948, 424348, 424668, 424988, 426908, 1146588, 184988, 1592988, 448348, 448988, 1352668, 2668, 2788, 2828, 2848, 2751388, 3028, 3048, 2751708, 2752028, 53468, 53788, 54428, 59548, 1535388, 1536348, 64348, 321628, 74548, 74588, 74908, 75228, 75548, 75868, 76188, 76508, 76828, 77148, 77748, 77788, 78108, 78708, 78748, 79348, 72308, 668, 2768, 177628, 2808, 177308, 445148, 59868]
> Object.new.methods.map(&:object_id) == [2078428, 1594268, 79388, 79708, 80028, 80348, 80668, 833308, 1940508, 1186268, 1942108, 824028, 82228, 82268, 82868, 83188, 83508, 83548, 81628, 80988, 81308, 177948, 424348, 424668, 424988, 426908, 1146588, 184988, 1592988, 448348, 448988, 1352668, 2668, 2788, 2828, 2848, 2751388, 3028, 3048, 2751708, 2752028, 53468, 53788, 54428, 59548, 1535388, 1536348, 64348, 321628, 74548, 74588, 74908, 75228, 75548, 75868, 76188, 76508, 76828, 77148, 77748, 77788, 78108, 78708, 78748, 79348, 72308, 668, 2768, 177628, 2808, 177308, 445148, 59868]
=> true
> Object.new.methods.map(&:object_id) == [2078428, 1594268, 79388, 79708, 80028, 80348, 80668, 833308, 1940508, 1186268, 1942108, 824028, 82228, 82268, 82868, 83188, 83508, 83548, 81628, 80988, 81308, 177948, 424348, 424668, 424988, 426908, 1146588, 184988, 1592988, 448348, 448988, 1352668, 2668, 2788, 2828, 2848, 2751388, 3028, 3048, 2751708, 2752028, 53468, 53788, 54428, 59548, 1535388, 1536348, 64348, 321628, 74548, 74588, 74908, 75228, 75548, 75868, 76188, 76508, 76828, 77148, 77748, 77788, 78108, 78708, 78748, 79348, 72308, 668, 2768, 177628, 2808, 177308, 445148, 59868]
> Object.new.methods.map(&:object_id) === [2078428, 1594268, 79388, 79708, 80028, 80348, 80668, 833308, 1940508, 1186268, 1942108, 824028, 82228, 82268, 82868, 83188, 83508, 83548, 81628, 80988, 81308, 177948, 424348, 424668, 424988, 426908, 1146588, 184988, 1592988, 448348, 448988, 1352668, 2668, 2788, 2828, 2848, 2751388, 3028, 3048, 2751708, 2752028, 53468, 53788, 54428, 59548, 1535388, 1536348, 64348, 321628, 74548, 74588, 74908, 75228, 75548, 75868, 76188, 76508, 76828, 77148, 77748, 77788, 78108, 78708, 78748, 79348, 72308, 668, 2768, 177628, 2808, 177308, 445148, 59868]
> Object.new.methods.map(&:object_id).eql? [2078428, 1594268, 79388, 79708, 80028, 80348, 80668, 833308, 1940508, 1186268, 1942108, 824028, 82228, 82268, 82868, 83188, 83508, 83548, 81628, 80988, 81308, 177948, 424348, 424668, 424988, 426908, 1146588, 184988, 1592988, 448348, 448988, 1352668, 2668, 2788, 2828, 2848, 2751388, 3028, 3048, 2751708, 2752028, 53468, 53788, 54428, 59548, 1535388, 1536348, 64348, 321628, 74548, 74588, 74908, 75228, 75548, 75868, 76188, 76508, 76828, 77148, 77748, 77788, 78108, 78708, 78748, 79348, 72308, 668, 2768, 177628, 2808, 177308, 445148, 59868]
> Object.new.methods.map(&:object_id) == [2078428, 1594268, 79388, 79708, 80028, 80348, 80668, 833308, 1940508, 1186268, 1942108, 824028, 82228, 82268, 82868, 83188, 83508, 83548, 81628, 80988, 81308, 177948, 424348, 424668, 424988, 426908, 1146588, 184988, 1592988, 448348, 448988, 1352668, 2668, 2788, 2828, 2848, 2751388, 3028, 3048, 2751708, 2752028, 53468, 53788, 54428, 59548, 1535388, 1536348, 64348, 321628, 74548, 74588, 74908, 75228, 75548, 75868, 76188, 76508, 76828, 77148, 77748, 77788, 78108, 78708, 78748, 79348, 72308, 668, 2768, 177628, 2808, 177308, 445148, 59868]
=> true
> Object.new.methods.map(&:object_id) === [2078428, 1594268, 79388, 79708, 80028, 80348, 80668, 833308, 1940508, 1186268, 1942108, 824028, 82228, 82268, 82868, 83188, 83508, 83548, 81628, 80988, 81308, 177948, 424348, 424668, 424988, 426908, 1146588, 184988, 1592988, 448348, 448988, 1352668, 2668, 2788, 2828, 2848, 2751388, 3028, 3048, 2751708, 2752028, 53468, 53788, 54428, 59548, 1535388, 1536348, 64348, 321628, 74548, 74588, 74908, 75228, 75548, 75868, 76188, 76508, 76828, 77148, 77748, 77788, 78108, 78708, 78748, 79348, 72308, 668, 2768, 177628, 2808, 177308, 445148, 59868]
=> true
> Object.new.methods.map(&:object_id).eql? [2078428, 1594268, 79388, 79708, 80028, 80348, 80668, 833308, 1940508, 1186268, 1942108, 824028, 82228, 82268, 82868, 83188, 83508, 83548, 81628, 80988, 81308, 177948, 424348, 424668, 424988, 426908, 1146588, 184988, 1592988, 448348, 448988, 1352668, 2668, 2788, 2828, 2848, 2751388, 3028, 3048, 2751708, 2752028, 53468, 53788, 54428, 59548, 1535388, 1536348, 64348, 321628, 74548, 74588, 74908, 75228, 75548, 75868, 76188, 76508, 76828, 77148, 77748, 77788, 78108, 78708, 78748, 79348, 72308, 668, 2768, 177628, 2808, 177308, 445148, 59868]
=> true
the hash?
the hash?
> Object.new.methods.hash === [:methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :instance_variable_set, :instance_variables, :instance_variable_get, :public_send, :method, :public_method, :singleton_method, :define_singleton_method, :extend, :to_enum, :enum_for, :ai, :<=>, :===, :=~, :!~, :awesome_inspect, :amazing_print, :eql?, :respond_to?, :freeze, :inspect, :object_id, :send, :to_s, :display, :nil?, :hash, :class, :singleton_class, :clone, :dup, :itself, :yield_self, :then, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :equal?, :!, :==, :instance_exec, :!=, :instance_eval, :__id__, :__send__
].hash
Object.new.methods.hash == Object.new.methods.take(Object.new.methods.length).hash
the hash?
> Object.new.methods.hash === [:methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :instance_variable_set, :instance_variables, :instance_variable_get, :public_send, :method, :public_method, :singleton_method, :define_singleton_method, :extend, :to_enum, :enum_for, :ai, :<=>, :===, :=~, :!~, :awesome_inspect, :amazing_print, :eql?, :respond_to?, :freeze, :inspect, :object_id, :send, :to_s, :display, :nil?, :hash, :class, :singleton_class, :clone, :dup, :itself, :yield_self, :then, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :equal?, :!, :==, :instance_exec, :!=, :instance_eval, :__id__, :__send__
].hash
=> true
Object.new.methods.hash == Object.new.methods.take(Object.new.methods.length).hash
=> true
- same object_ids
- equality comparisons
- same hash
Now even the returned methods, the pasted array of vanilla symbols seem the same from every angle we've tried to inspect them.
It needs to quack like a Symbol
It needs to quack like a Symbol
- have the class Symbol
It needs to quack like a Symbol
- have the class Symbol
- have the same object_id as the Symbol it represents
It needs to quack like a Symbol
- have the class Symbol
- have the same object_id as the Symbol it represents
- have access to the original method and object
class SymbolLikeMethod < SimpleDelegator
attr_reader :object, :symbol
def initialize(object, symbol)
super(symbol)
@symbol = symbol
@object = object
end
def class
Symbol
end
def object_id
symbol.object_id
end
def pretty_print
meth = object.method(symbol)
[meth.name, meth.parameters, meth.owner].join(" ")
end
end
sym = SymbolLikeMethod.new(1, :to_s)
[sym].hash == [:to_s].hash
=> true
sym.hash == :to_s.hash
=> true
sym.object_id == :to_s.object_id
=> true
sym.class == :to_s.class
=> true
sym.pretty_print
=> ":to_s [[:rest]] Integer"
let's look at ap
> require 'pry'
> binding.pry
> show-source ap
def ap(object, options = {})
puts object.ai(options)
object unless AwesomePrint.console?
end
let's look at ai
then on Kernel
> show-source Kernel
Number of monkeypatches: 9. Use the `-a` option to display all available monkeypatches
Number of lines: 21
module Kernel
def ai(options = {})
ap = AwesomePrint::Inspector.new(options)
awesome = ap.awesome self
if options[:html]
awesome = "<pre>#{awesome}</pre>"
awesome = awesome.html_safe if defined? ActiveSupport
end
awesome
end
alias :awesome_inspect :ai
def ap(object, options = {})
puts object.ai(options)
object unless AwesomePrint.console?
end
alias :awesome_print :ap
module_function :ap
end
def awesome(object)
if Thread.current[AP].include?(object.object_id)
nested(object)
else
begin
Thread.current[AP] << object.object_id
unnested(object)
ensure
Thread.current[AP].pop
end
end
end
#nested
and #unnested
def nested(object)
case printable(object)
when :array then @formatter.colorize('[...]', :array)
when :hash then @formatter.colorize('{...}', :hash)
when :struct then @formatter.colorize('{...}', :struct)
else @formatter.colorize("...#{object.class}...", :class)
end
end
def unnested(object)
@formatter.format(object, printable(object))
end
class Inspector
def initialize(options = {})
# [... SNIP ...]
@formatter = AwesomePrint::Formatter.new(self)
we see this is an AwesomePrint::Formatter
> show-source AwesomePrint::Formatter
class Formatter
def format(object, type = nil)
core_class = cast(object, type)
awesome = if core_class != :self
send(:"awesome_#{core_class}", object) # Core formatters.
else
awesome_self(object, type) # Catch all that falls back to object.inspect.
end
awesome
end
CORE = [:array, :bigdecimal, :class, :dir, :file, :hash, :method, :rational, :set, :struct, :unbound_method]
def cast(object, type)
CORE.grep(type)[0] || :self
end
def format(object, type = nil)
awesome_array(object)
end
def awesome_array(a)
Formatters::ArrayFormatter.new(a, @inspector).format
end
def format
if array.empty?
'[]'
elsif methods_array?
methods_array
else
simple_array
end
end
private
def methods_array?
array.instance_variable_defined?('@__awesome_methods__')
end
def methods_array?
array.instance_variable_defined?('@__awesome_methods__')
end
now our hunt has to change tactics.
- pry's show-source
- bundle info
- grep/ag
➜ bundle info awesome_print
* awesome_print (1.8.0)
Summary: Pretty print Ruby objects with proper indentation and colors
Homepage: https://github.com/awesome-print/awesome_print
Path: /home/mark/.asdf/installs/ruby/2.6.4/lib/ruby/gems/2.6.0/gems/awesome_print-1.8.0
➜ cd /home/mark/.asdf/installs/ruby/2.6.4/lib/ruby/gems/2.6.0/gems/awesome_print-1.8.0
➜ ag @__awesome_methods__
[...SNIP...]
awesome_print/core_ext/object.rb
18: methods.instance_variable_set(:@__awesome_methods__, self)
class Object
%w(methods private_methods protected_methods public_methods singleton_methods).each do |name|
original_method = instance_method(name)
define_method name do |*args|
methods = original_method.bind(self).call(*args)
methods.instance_variable_set(:@__awesome_methods__, self)
methods.extend(AwesomeMethodArray)
methods
end
end
end
1.methods
define_method name do |*args| # def methods(*args)
methods = original_method.bind(self).call(*args) # methods = [ :-@, :**, :<=>, :upto, :<<, :<=, :>=, :==, :chr, :===, :>>, :[], :%, :&, :inspect, :*, :+, :ord, :-, :/, :size, :succ, :<, :>, :to_int, :coerce, :to_s, :to_i, :to_f, :divmod, :to_r, :fdiv, :modulo, :remainder, :abs, :magnitude, :integer?, :floor, :ceil, :round, :truncate, :^, :odd?, :even?, :allbits?, :anybits?, :nobits?, :downto, :times, :pred, :pow, :bit_length, :digits, :numerator, :denominator, :rationalize, :gcd, :lcm, :gcdlcm, :next, :div, :|, :~, :imag, :abs2, :+@, :phase, :to_c, :polar, :angle, :conjugate, :conj, :pretty_print, :pretty_print_cycle, :eql?, :singleton_method_added, :i, :real?, :zero?, :nonzero?, :finite?, :infinite?, :step, :positive?, :negative?, :clone, :dup, :arg, :quo, :rectangular, :rect, :real, :imaginary, :between?, :clamp, :__binding__, :singleton_methods, :methods, :pry, :protected_methods, :private_methods, :to_yaml, :public_methods, :pretty_print_inspect, :pretty_print_instance_variables, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :instance_variable_set, :instance_variables, :instance_variable_get, :public_send, :method, :public_method, :singleton_method, :debugger, :define_singleton_method, :byebug, :remote_byebug, :pretty_inspect, :extend, :to_enum, :enum_for, :ai, :=~, :!~, :respond_to?, :awesome_inspect, :awesome_print, :freeze, :object_id, :send, :display, :nil?, :hash, :class, :singleton_class, :itself, :yield_self, :then, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :equal?, :!, :instance_exec, :!=, :instance_eval, :__id__, :__send__]
methods.instance_variable_set(:@__awesome_methods__, self) # methods.instance_eval { @__awesome_methods__ = 1 }
methods.extend(AwesomeMethodArray) # methods.extend(AwesomeMethodArray)
methods # methods
end # end
1.methods
def methods(*args)
methods = [ :-@, :**, :<=>, :upto, :<<, :<=, :>=, :==, :chr, :===, :>>, :[], :%, :&, :inspect, :*, :+, :ord, :-, :/, :size, :succ, :<, :>, :to_int, :coerce, :to_s, :to_i, :to_f, :divmod, :to_r, :fdiv, :modulo, :remainder, :abs, :magnitude, :integer?, :floor, :ceil, :round, :truncate, :^, :odd?, :even?, :allbits?, :anybits?, :nobits?, :downto, :times, :pred, :pow, :bit_length, :digits, :numerator, :denominator, :rationalize, :gcd, :lcm, :gcdlcm, :next, :div, :|, :~, :imag, :abs2, :+@, :phase, :to_c, :polar, :angle, :conjugate, :conj, :pretty_print, :pretty_print_cycle, :eql?, :singleton_method_added, :i, :real?, :zero?, :nonzero?, :finite?, :infinite?, :step, :positive?, :negative?, :clone, :dup, :arg, :quo, :rectangular, :rect, :real, :imaginary, :between?, :clamp, :__binding__, :singleton_methods, :methods, :pry, :protected_methods, :private_methods, :to_yaml, :public_methods, :pretty_print_inspect, :pretty_print_instance_variables, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :instance_variable_set, :instance_variables, :instance_variable_get, :public_send, :method, :public_method, :singleton_method, :debugger, :define_singleton_method, :byebug, :remote_byebug, :pretty_inspect, :extend, :to_enum, :enum_for, :ai, :=~, :!~, :respond_to?, :awesome_inspect, :awesome_print, :freeze, :object_id, :send, :display, :nil?, :hash, :class, :singleton_class, :itself, :yield_self, :then, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :equal?, :!, :instance_exec, :!=, :instance_eval, :__id__, :__send__]
methods.instance_variable_set(:@__awesome_methods__, 1)
methods.extend(AwesomeMethodArray)
methods
end
Later on when
awesome_print
uses this return value, it now has access to the specific instance that has been set. Via @awesome_methods. In our case1
. And it can use that instance variable to do all its clever formatting stuff.
back to AwesomePrint::Formatters::ArrayFormatter#format
def format
if array.empty?
'[]'
elsif methods_array?
methods_array
else
simple_array
end
end
> show-source AwesomePrint::Formatters::ArrayFormatter#methods_array
def methods_array
array.map!(&:to_s).sort!
data = generate_printable_tuples.join("\n")
"[\n#{data}\n#{outdent}]"
end
def generate_printable_tuples
tuples.map.with_index do |item, index|
tuple_prefix(index, width(tuples)).tap do |temp|
indented { temp << tuple_template(item) }
end
end
end
def tuples
@tuples ||= array.map { |name| generate_tuple(name) }
end
def generate_tuple(name)
meth = case name
when Symbol, String
find_method(name)
end
meth ? method_tuple(meth) : [name.to_s, '(?)', '?']
end
def find_method(name)
object = array.instance_variable_get('@__awesome_methods__')
meth = begin
object.method(name)
rescue NameError, ArgumentError
nil
end
meth || begin
object.instance_method(name)
rescue NameError
nil
end
end
def method_tuple(method)
if method.respond_to?(:parameters)
args = method.parameters.inject([]) do |arr, (type, name)|
name ||= (type == :block ? 'block' : "arg#{arr.size + 1}")
arr << case type
when :req then name.to_s
when :opt, :rest then "*#{name}"
when :block then "&#{name}"
else '?'
end
end
else
args = (1..method.arity.abs).map { |i| "arg#{i}" }
args[-1] = "*#{args[-1]}" if method.arity < 0
end
if method.to_s =~ /(Unbound)*Method: (.*)[#\.]/
unbound = $1 && '(unbound)'
klass = $2
if klass && klass =~ /(\(\w+:\s.*?\))/ # Is this ActiveRecord-style class?
klass.sub!($1, '') # Yes, strip the fields leaving class name only.
end
owner = "#{klass}#{unbound}".gsub('(', ' (')
end
[method.name.to_s, "(#{args.join(', ')})", owner.to_s]
end
You can find the answer to nearly any ruby mystery just using the following:
- byebug
- binding.pry
- show-source
- bundle info
- ag or grep