ObjectSpace.each_object(Foo).count - ruby-on-rails

I'am trying to figure out ObjectSpace.each_object
In console:
class Foo; end
Foo.new
ObjectSpace.each_object(Foo).count
=> 1
GC.start
ObjectSpace.each_object(Foo).count
=> 1
I've seen examples and I know that the second count should be 0.
Any ideas what is going on here?
Thanks.

It depends on your console.
IRB
The last result is saved as _, even if it hasn't been explicitely assigned.
Running GC.start won't remove the last object :
irb(main):001:0> class Foo; end
=> nil
irb(main):002:0>
irb(main):003:0* Foo.new
=> #<Foo:0x007fca7a309f98>
irb(main):004:0> p ObjectSpace.each_object(Foo).count; GC.start; p ObjectSpace.each_object(Foo).count
1
1
=> 1
irb(main):005:0> p ObjectSpace.each_object(Foo).count; GC.start; p ObjectSpace.each_object(Foo).count
1
0
=> 0
Pry
You can access the last result and the second to last result with _ and __ :
[1] pry(main)> 'a'
=> "a"
[2] pry(main)> 'b'
=> "b"
[3] pry(main)> p _, __
"b"
"a"
=> ["b", "a"]
Pry saves all the 100 last results in _out_ Pry::HistoryArray:
[1] pry(main)> class Foo; end
=> nil
[2] pry(main)> Foo.new
=> #<Foo:0x007fd093102118>
[3] pry(main)> ObjectSpace.each_object(Foo).count
=> 1
[4] pry(main)> GC.start
=> nil
[5] pry(main)> ObjectSpace.each_object(Foo).count
=> 1
[6] pry(main)> _out_[2]
=> #<Foo:0x007fd093102118>
You can use _out_.pop! to remove its last element :
[1] pry(main)> class Foo; end
=> nil
[2] pry(main)> Foo.new
=> #<Foo:0x007fa90b1ad360>
[3] pry(main)> ObjectSpace.each_object(Foo).count
=> 1
[4] pry(main)> GC.start
=> nil
[5] pry(main)> ObjectSpace.each_object(Foo).count
=> 1
[6] pry(main)> 5.times{_out_.pop!}
=> 5
[7] pry(main)> GC.start
=> nil
[8] pry(main)> ObjectSpace.each_object(Foo).count
=> 0
Inside a script
If you execute :
class Foo; end
Foo.new
p ObjectSpace.each_object(Foo).count
GC.start
p ObjectSpace.each_object(Foo).count
inside a script, you get :
1
0

GC.start does not force the garbage collector to start.
It is slightly unclear from the documentation, but it just instructs the engine to schedule a garbage collection. That said, one can not rely on GC.start would immediately remove objects from the heap.

Related

Why does this where query no longer work properly for ShopifyAPI?

I am trying to do a simple where query on both the Checkout class and Order class via the REST ShopifyAPI, but it keeps returning inaccurate data.
Here are two examples:
[12] pry(main)> Order.count
=> 9
[13] pry(main)> Order.where(created_at: (Time.now - 1.minute)..(Time.now)).count
=> 9
[14] pry(main)> Order.where(created_at: (Time.now - 1.second)..(Time.now)).count
=> 9
[15] pry(main)> Order.first.created_at
=> "2021-05-15T02:59:36-05:00"
[16] pry(main)> Order.last.created_at
=> "2021-04-23T02:43:44-05:00"
And the same thing for Checkout:
[8] pry(main)> Checkout.where(created_at: (Time.now - 24.hours)..(Time.now)).count
=> 6
[9] pry(main)> Checkout.where(created_at: (Time.now - 10.minutes)..(Time.now)).count
=> 6
[10] pry(main)> Checkout.where(created_at: (Time.now - 1.minute)..(Time.now)).count
=> 6
[11] pry(main)> Checkout.count
=> 6
[18] pry(main)> Checkout.first.created_at
=> "2021-04-29T00:13:16-05:00"
[19] pry(main)> Checkout.last.created_at
=> "2021-05-15T03:00:37-05:00"
What could be the cause of this?
Edit 1
Strangely enough, this issue seems to not show itself when I try another model like Product:
[28] pry(main)> Product.where(title: "High Coverage Foundation").count
=> 1
[29] pry(main)> Product.count
=> 6
That's the correct feedback I was expecting. I am expecting something similar for the Order model too, but for some reason it isn't working properly.
I have restarted my local terminal session, and reinstalled my Shopify-api-cli...to no avail.
Edit 2
See more examples from both classes that show the existence of those objects which indicates that the query should work.
[51] pry(main)> Order.first.id
=> 3779683877046
[52] pry(main)> Order.last.id
=> 3741986750646
[53] pry(main)> Order.first.created_at
=> "2021-05-15T02:59:36-05:00"
[54] pry(main)> Order.last.created_at
=> "2021-04-23T02:43:44-05:00"
[55] pry(main)> Checkout.first.id
=> "ef8dd57a1b1911da9077df7789698847"
[56] pry(main)> Checkout.last.id
=> "7133c7aeb0ff3b4b506c2a66e4190ee3"
[57] pry(main)> Checkout.first.created_at
=> "2021-04-29T00:13:16-05:00"
[58] pry(main)> Checkout.last.created_at
=> "2021-05-15T03:00:37-05:00"
Edit 3
So it seems that it works for queries done on attributes that have a string, but not an integer and datetime is inconsistent:
[79] pry(main)> Order.where(cart_token: '36e017f94cbf19bee298d61334b68225').count
=> 1 // #RIGHT
[80] pry(main)> Order.where(created_at: '2021-05-15T02:59:36-05:00').count
=> 9 // #WRONG
[81] pry(main)> Order.where(current_total_price: 294.14).count
=> 9 // #WRONG
[82] pry(main)> Order.where(email: 'alex#test.com').count
=> 1 // #RIGHT
[83] pry(main)> Order.where(processed_at: '2021-05-15T02:59:35-05:00').count
=> 3 // #RIGHT STRANGELY ENOUGH
[97] pry(main)> Order.where(processed_at: '2021-05-15T02:59:35-05:00').first.id
=> 3779683877046 // #RIGHT
[98] pry(main)> Order.where(processed_at: '2021-05-15T02:59:35-05:00').last.id
=> 3779668639926 // #RIGHT
I got a response on Shopify's official forum which can be seen here.
TL;DR, Shopify's rubygem doesn't implement ranged dates exactly like ActiveRecord does, they use created_at_min and created_at_max attributes on the model.
So the correct query for the ShopifyAPI for that where query is:
ShopifyAPI::Order.where(created_at_min: Time.now - 6.days, created_at_max: Time.now).count

what is << on string and integer object in ruby?

what is the use of << in ruby on integer and string object.
I tried the following in irb
irb(main):001:0> a=1
=> 1
irb(main):002:0> b=3
=> 3
irb(main):003:0> a<<b
=> 8
irb(main):004:0> a+b
=> 4
irb(main):005:0> a="aa"
=> "aa"
irb(main):006:0> b="bb"
=> "bb"
irb(main):007:0> a<<b
=> "aabb"
irb(main):008:0> a+b
=> "aabbbb"
On integers, it is the bit-shift-left operator: a << b is (barring overflows) equivalent to a * (2 ** b).
On strings and arrays, it is append (concatenate-to-this) operator.

The loading another class has side effect with mongoid

Can somebody explain me this:
User < AbstractUser
store_in collection: 'users'
InvitedUser < AbstractUser
store_in collection: 'invited_users'
Then when I am loading the InvitedUser while working with a user object I have the following side effect.
[3] pry(#<UserInvitationsController>)> User.collection
=> #<Moped::Collection:0x007f8f008f21e0
...
#name="users">
[4] pry(#<UserInvitationsController>)> InvitedUser
=> false
[5] pry(#<UserInvitationsController>)> User.collection
=> #<Moped::Collection:0x007f8f00202d30
#name="invited_users">
And from then on the mongoid operations on User won't work properly...
I also reported an issue on github:
https://github.com/mongoid/mongoid/issues/3408
It seems that the side effect is caused by the common ancestor.
Without common ancestor everything is like it should be.
=> User
[2] pry(main)> User.collection.name
=> "users"
[3] pry(main)> InvitedUser.collection.name
=> "invited_users"
[4] pry(main)> User.collection.name
=> "users"
[5] pry(main)> InvitedUser.collection.name
=> "invited_users"
[6] pry(main)> exit
With common ancestor the side effect appears
→ ./bin/rails c
Loading development environment (Rails 4.0.0)
[1] pry(main)> User.collection.name
=> "users"
[2] pry(main)> InvitedUser.collection.name
=> "invited_users"
[3] pry(main)> User.collection.name
=> "invited_users"
[4] pry(main)> InvitedUser.collection.name
=> "invited_users"
[5] pry(main)>

Rails serialization of Range of integers is broken

I need to serialize ruby Ranges using YAML, in a rails context.
I wanted to check if ranges of integers and ranges of strings were serialized properly.
Here was my test:
# classic irb
require 'yaml' # => true
YAML::VERSION # => "0.60"
YAML.dump(1..2) # => "--- !ruby/range \nbegin: 1\nend: 2\nexcl: false\n"
YAML.dump("1".."2") # => "--- !ruby/range \nbegin: \"1\"\nend: \"2\"\nexcl: false\n"
The two outputs are dutifully distinct, so I got forward and coded it inside my rails application.
However it seems that within a rails context, ruby forgets how to properly serialize a range of integers!
# ./script/rails console
Rails::VERSION::STRING # => "3.0.15"
RUBY_VERSION # => "1.8.7"
YAML::VERSION # => "0.60"
YAML.dump(1..2) # => "--- !ruby/range\n begin: 1\n end: 2\n excl: false"
YAML.dump("1".."2") # => "--- !ruby/range\n begin: 1\n end: 2\n excl: false"
# The two outputs are identical, the distinction between integers and strings is lost!
Both ruby and ruby on rails seem to use the same version of the YAML library.
If I don't get it wrong, my version of ruby doesn't support switching between multiple coder engines.
I have a few questions:
What is the cause of this difference?
Does this problem arise with newer versions of ruby / rails?
How could I fix that properly, in a compatible manner?
Thank you for your help.
A range is a Ruby internal, not a YAML base type like an integer or string. Rather than encode the range as you are, use its start and end points and reconstruct the range on the receiving end.
I use something like:
[1] (pry) main: 0> range = 0..1
=> 0..1
[2] (pry) main: 0> require 'yaml'
=> true
[3] (pry) main: 0> YAML.dump(range)
=> "--- !ruby/range\nbegin: 0\nend: 1\nexcl: false\n"
[4] (pry) main: 0> YAML.dump({'min' => range.min, 'max' => range.max})
=> "---\nmin: 0\nmax: 1\n"
And then I can recreate the range on the receiving side using something like:
Range.new(*YAML.load(YAML.dump({'min' => range.min, 'max' => range.max})).values)
=> 0..1
or this if you're not sure that 'min' and 'max' will be in the right order:
[19] (pry) main: 0> Range.new(*YAML.load(YAML.dump({'min' => range.min, 'max' => range.max})).values_at('min', 'max'))
=> 0..1
Adding some information regarding Ruby 1.9.3+ serializing ranges of characters:
[2] (pry) main: 0> range = '0'..'1'
=> "0".."1"
[3] (pry) main: 0> YAML.dump(range)
=> "--- !ruby/range\nbegin: '0'\nend: '1'\nexcl: false\n"
[5] (pry) main: 0> RUBY_VERSION
=> "1.9.3"
And again with 1.9.2+:
[2] (pry) main: 0> range = '0'..'1'
=> "0".."1"
[3] (pry) main: 0> YAML.dump(range)
=> "--- !ruby/range \nbegin: \"0\"\nend: \"1\"\nexcl: false\n"
[4] (pry) main: 0> RUBY_VERSION
=> "1.9.2"
And, the workaround maintains the range start/end types:
[6] (pry) main: 0> Range.new(*YAML.load(YAML.dump({'min' => range.min, 'max' => range.max})).values_at('min', 'max'))
=> "0".."1"
In both cases the YAML_VERSION is 0.60.

Is there equivalent for PHP's print_r in Ruby / Rails?

In PHP you can do:
print_r($var) or vardump($var)
which prints "human-readible" information about variable.
Is there equivalent functions / helpers for those in Ruby / Rails ?
In Rails templates you can do
<%= debug an_object %>
and it will do nice HTML PRE output.
Try using pp.
You will need to require it in scripts (or in irb if your .irbc doesn't already do this):
require 'pp'
Then you can 'PrettyPrint' an object thus:
pp object
Instead of requiring 'pp' and using pp, you can simply do
p object
Tested example
require 'pp'
class A
def initialize
#a = 'somevar'
#b = [1,2,3]
#c = {'var' => 'val'}
end
end
a = A.new
pp a # Gives -> #<A:0x2c6d048 #a="somevar", #b=[1, 2, 3], #c={"var"=>"val"}>
p a # Gives -> #<A:0x2c6d048 #a="somevar", #b=[1, 2, 3], #c={"var"=>"val"}>. No need to require 'pp'
There's the method inspect which helps. Sometimes calling the to_s method on an object will help (to_s returns a string representation of the object). You can also query methods, local_variables, class_variables, instance_variables, constants and global_variables.
p ['Hello',"G'day",'Bonjour','Hola'].inspect
# >> "[\"Hello\", \"G'day\", \"Bonjour\", \"Hola\"]"
p ['Hello',"G'day",'Bonjour','Hola'].to_s
# >> "HelloG'dayBonjourHola"
p Array.new.methods
# >> ["select", "[]=", "inspect", "compact"...]
monkey = 'baboon'
p local_variables
# >> ["monkey"]
class Something
def initialize
#x, #y = 'foo', 'bar'
##class_variable = 'gorilla'
end
end
p Something.class_variables
# >> ["##class_variable"]
s = Something.new
p s.instance_variables
# >> ["#x", "#y"]
p IO.constants
# >> ["TRUNC", "SEEK_END", "LOCK_SH"...]
p global_variables
# >> ["$-d", "$\"", "$$", "$<", "$_", "$-K"...]
I know this is an old post, but it is the first thing that Google pops up when searching for "Ruby equivalent of PHP print_r". I'm using Ruby in the command line mode, and there's really not a very good equivalent. "pp" is ok for fairly simple structures, but as soon as you start nesting hashes in arrays in hashes in more arrays, it turns into a jumble pretty fast. Since I haven't found a good emulation of print_r, I wrote one myself. It's good enough for my purposes, not overly complicated and I thought I'd share it to save other people some headache. Compare the output with the real PHP print_r
def print_r(inHash, *indent)
#indent = indent.join
if (inHash.class.to_s == "Hash") then
print "Hash\n#{#indent}(\n"
inHash.each { |key, value|
if (value.class.to_s =~ /Hash/) || (value.class.to_s =~ /Array/) then
print "#{#indent} [#{key}] => "
self.print_r(value, "#{#indent} ")
else
puts "#{#indent} [#{key}] => #{value}"
end
}
puts "#{#indent})\n"
elsif (inHash.class.to_s == "Array") then
print "Array\n#{#indent}(\n"
inHash.each_with_index { |value,index|
if (value.class.to_s == "Hash") || (value.class.to_s == "Array") then
print "#{#indent} [#{index}] => "
self.print_r(value, "#{#indent} ")
else
puts "#{#indent} [#{index}] => #{value}"
end
}
puts "#{#indent})\n"
end
# Pop last indent off
8.times {#indent.chop!}
end
Here's an example (made messy on purpose to show why the PHP print_r is so nice):
carTools = [ "Socket Set", "Combination Wrenches", "Oil Filter puller", "Brake Compressor" ]
houseTools =[ "Circular Saw", "Miter Saw", "Drill" ]
garageItems = Hash["Car1" => "Ford Mustang", "Car2" => "Honda Civic", "Bike1" => "IronHorse"]
garageItems["Tools"] = Hash["Car Tools" => carTools, "House Tools" => houseTools]
constructionSupplies = Hash["Plywood" => ["3/4\" T&G Plywood Sheets", "1/2\" Plywood Sheets"],
"Boards" => ["2x4s", "2x6s", "Engineered I-Joists"],
"Drywall" => ["4x8 1/2\" Sheetrock", "Mesh tape", "Paper tape", "Joint compount"]]
carParts = Hash["Mustang" => ["Clutch", "Transmission", "3.55 Ring & Pinion Gears", "Differential", "30# Injectors", "Pro-M 77mm MAF"]]
garageItems["Supplies"] = ["Oil", "WD40", constructionSupplies, carParts, "Brake Fluid"]
print_r(garageItems)
Output of print_r (actually comprehensible by a human):
Hash
(
[Car1] => Ford Mustang
[Car2] => Honda Civic
[Bike1] => IronHorse
[Tools] => Hash
(
[Car Tools] => Array
(
[0] => Socket Set
[1] => Combination Wrenches
[2] => Oil Filter puller
[3] => Brake Compressor
)
[House Tools] => Array
(
[0] => Circular Saw
[1] => Miter Saw
[2] => Drill
)
)
[Supplies] => Array
(
[0] => Oil
[1] => WD40
[2] => Hash
(
[Plywood] => Array
(
[0] => 3/4" T&G Plywood Sheets
[1] => 1/2" Plywood Sheets
)
[Boards] => Array
(
[0] => 2x4s
[1] => 2x6s
[2] => Engineered I-Joists
)
[Drywall] => Array
(
[0] => 4x8 1/2" Sheetrock
[1] => Mesh tape
[2] => Paper tape
[3] => Joint compount
)
)
[3] => Hash
(
[Mustang] => Array
(
[0] => Clutch
[1] => Transmission
[2] => 3.55 Ring & Pinion Gears
[3] => Differential
[4] => 30# Injectors
[5] => Pro-M 77mm MAF
)
)
[4] => Brake Fluid
)
)
Check out the guide for debugging rails:
http://guides.rubyonrails.com/debugging_rails_applications.html
hints:
script/console is great to try stuff in the context of your app
script/server --debugger to start the server with a debugger turned on, you can then use 'debug' in your code to break into an interactive shell
One approach I lean on a lot is this:
logger.debug "OBJECT: #{an_object.to_yaml}"
Easy to read, although it can get a little unwieldy for large objects.
Guess I'm a little late to this, but what about logger.info [debug|warning]? Use this from Controllers and Models. It will show up in your log files (development.log when in dev mode); and the above mentioned <%= debug("str: " + str) %> for views.
These aren't exact answers to your questions but you can also use script/console to load your rails app in to an interactive session.
Lastly, you can place debugger in a line of your rails application and the browser will "hang" when your app executes this line and you'll be able to be in a debug session from the exact line your placed your debugger in the source code.

Resources