How to use interactive_editor when REPL console is run in context of a particular object - ruby

I am trying to programmatically launch a console such that:
Its context is bound to a particular object (link to Stack Overflow).
It allows me to use tools (i.e. vim command) provided by the interactive_editor Gem (link to GitHub).
It would be appear that the two conditions I am trying to meet are mutually exclusive. Below I write a script that fires up a REPL that is bound to the context of a [1,2,3] list.
# test.rb
require 'ripl'
require 'interactive_editor'
Ripl.start :binding => [1,2,3].instance_eval { binding }
If you run ruby test.rb, you can see that you are in the context of [1,2,3]:
>> self
=> [1, 2, 3]
>> map { |a| a * 2 }
=> [2, 4, 6]
But if you try using interactive_editor's features:
>> vim "something"
=> [1, 2, 3]
This last line fires up vim and actually writes to the file "something" (without my explicit saving):
# something
---
- 1
- 2
- 3
Is there any way for me to resolve this problem? Should I file this as an issue on the interactive_editor Gem? The same kinds of error occur when I use IRB along with interactive_editor or irbtools.
My guess is that changing the context makes it rather difficult for interactive_editor to resolve its object definitions but I am not sure how this works.
Thanks in advance and please let me know if I omitted important information.
ruby 2.1.5p273 (2014-11-13 revision 48405) [x86_64-darwin14.0]
iteractive_editor (0.0.10)
irbtools (2.0.1, 1.7.1)
ripl (0.7.1)
ripltools (0.7.0)
I am running OS X Yosemite 10.10.3 but have managed to replicate this issue on several other Linux boxes.

I found a way around this:
def edit(*args)
system("$EDITOR #{args.join(' ')")
end
This still doesn't explain why I can't get this example to work with interactive_prompt.

Related

Ruby NoMethodError exception calls #inspect by default

I have found a weird problem in Ruby and I'm not quite sure if it is an issue or it's a feature introduced in recent Ruby versions.
Basically when we call an undefined method, we get an undefined method error as expected in Ruby. The issue is that it also calls inspect and prints out the object and all of its attributes/values. If my object is a complex one, it takes really long time to finish printing everything out and in many times it causes my local rails server to hang, especially when there is an attribute holding binary data. This issue does not seem to happen with Ruby 2.6 but Ruby >= 2.7.
For simple objects, that's not a problem but I'm specifically having the issue with this gem: puppeteer-ruby. Each object in this gem has lots of attributes and dependencies.
Here is an example, I run the following code in IRB with different Ruby version and getting different exceptions:
require 'puppeteer-ruby'
browser = Puppeteer.launch(headless: true)
browser.foo
Ruby 2.6.6
NoMethodError: undefined method `foo' for #<Puppeteer::Browser:0x00007fce2d553b30>
Did you mean? for
Ruby 3.0.0
(irb):9:in `<main>': undefined method `foo' for #<Puppeteer::Browser:0x00007f9300550740 #ignore_https_errors=false, #default_viewport=#<Puppeteer::Viewport:0x00007f92ffbf8e90 #width=800, #height=600, #device_scale_factor=1.0, #is_mobile=false, #has_touch=false, #is_landscape=false>, #process=#<Puppeteer::BrowserRunner::BrowserProcess:0x00007f92fc5ae448 #spawnargs=["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", "--disable-background-networking", "--enable-features=NetworkService,NetworkServiceInProcess", "--disable-background-timer-throttling", "--disable-backgrounding-occluded-windows", "--disable-breakpad", "--disable-client-side-phishing-detection", "--disable-component-extensions-with-background-pages", "--disable-default-apps", "--disable-dev-shm-usage", "--disable-extensions", "--disable-features=Translate", "--disable-hang-monitor", "--disable-ipc-flooding-protection", "--disable-popup-blocking", "--disable-prompt-on-repost", "--disable-renderer-backgrounding", "--disable-sync", "--force-color-profile=srgb", "--metrics-recording-only", "--no-first-run", "--enable-automation", "--password-store=basic", "--use-mock-keychain", "--enable-blink-features=IdleDetection", "--headless", "--hide-scrollbars", "--mute-audio", "about:blank", "--remote-debugging-port=0", "--user-data-dir=/var/folders/qn/kx4kb8xx5x13gx77yy2q56fr0000gn/T/puppeteer_dev_chrome_profile-20210910-25051-m7mnxb"], #stdout=#<IO:fd 24>, #stderr=#<IO:fd 26>,......very long text after this..
Thats interesting - inspect has always printed internal variables.
In the blame the last change to inspect was 9 years ago: rb_object_inspect#704
A simple script using 2.6:
> docker run -it ruby:2.6.6-alpine sh
#> ruby -v
ruby 2.6.6p146 (2020-03-31 revision 67876) [x86_64-linux-musl]
#> irb
irb(main):001:0> class Foo; def initialize(message); #message = message; end; end
=> :initialize
irb(main):002:0> Foo.new('hello').foo
NoMethodError (undefined method `foo' for #<Foo:0x00007f35e20e0280 #message="hello">)
Did you mean? for
Though looking at the source for Puppeteer::Browser it seems they changed to a pure ruby implementation of the browser around 2 years ago. When they did that they introduced a lot of ivars to the class. Perhaps the version you're using changed between updating ruby from 2.6 to 3.0?
A simple fix would be to monkey patch inspect on Puppeteer::Browser, or send a PR to the maintainer - looks like the project is active on GitHub.

Strange results for the Gem.latest_version_for(name) method

I am working on a gem related utility and I have observed strange results using Gem.latest_version_for method. Here are some observations under irb:
irb(main):001:0> Gem.latest_version_for('rails').to_s
=> "5.2.2"
irb(main):002:0> Gem.latest_version_for('gosu').to_s
=> "0.7.38"
Note how the first line, gets the correct version of rails, 5.2.2 as I write this and checking with rubygems.org confirms this. The query for the gosu gem returns 0.7.38 which is wildly wrong. The correct answer should be 0.14.4
I am at a loss to explain what is happening here.
I can confirm that my host is https://rubygems.org and
C:\Sites\mysh
8 mysh>ruby --version
ruby 2.3.3p222 (2016-11-21 revision 56859) [i386-mingw32]
C:\Sites\mysh
9 mysh>gem --version
2.5.2
The latest version available for i386-mingw32 platform is 0.7.38. You'll note this comports with what your ruby version is reported as.
https://rubygems.org/gems/gosu/versions
latest_version_for calls latest_spec_for, which calls Gem::SpecFetcher.spec_for_dependency with only the name of the gem as an argument. spec_for_dependency takes another argument, matching_platform, which defaults to true.
It looks like latest_version_for is scoped to your current platform thru that chain, with the matching_platform default. The gem install command might treat i386/x386 as the same/equivalent and allow them.
spec_for_dependency
if matching_platform is false, gems for all platforms are returned
You should be able to mirror the latest_spec_for method and pass in the multi_platform argument to override. Something like
dependency = Gem::Dependency.new name
fetcher = Gem::SpecFetcher.fetcher
spec_tuples, _ = fetcher.spec_for_dependency dependency, true # true added here
With the excellent help of Jay Dorsey, I think I have made some progress here. What I need to say is too large to fit in a comment and is the actual answer to the question about the odd behavior. Well at least I am pretty sure that it is.
As mentioned above: latest_version_for calls latest_spec_for, which calls Gem::SpecFetcher.spec_for_dependency.
The key is that that method then calls Gem::SpecFetcher.search_for_dependency. This is a long rambling method. I want to focus of one line that occurs after the specs have be obtained:
tuples = tuples.sort_by { |x| x[0] }
This sorts the tuples which are an array of [spec, source] arrays. It sorts them in ascending version/platform (as far as I can tell)
Now we return to the Gem class method latest_spec_for(name) and in particular the line:
spec, = spec_tuples.first
This grabs the first sub-array and keeps the spec and discards the source.
Note that it grabs the first element. The one with the lowest version number. This is normally not a problem because for the vast majority of gems, there will be only one spec present. Not so for the gosu gem. Here there are three due to the fact that gosu contains platform specific code. It seems to grab specs for the two Gem platforms ("ruby" and "x86-mingw32") and also the ruby platform (i386-mingw32).
To test my idea, I created the file glmp.rb (get last monkey patch) Here it is:
# The latest_spec_for(name) monkey patch.
module Gem
# Originally in File rubygems.rb at line 816
def self.latest_spec_for(name)
dependency = Gem::Dependency.new name
fetcher = Gem::SpecFetcher.fetcher
spec_tuples, = fetcher.spec_for_dependency dependency
spec_tuples[-1][0]
end
end
Now I know monkey patching is frowned upon, but for now this is just to test the idea. Here are my results:
36 mysh>=Gem.latest_version_for('gosu')
Gem::Version.new("0.7.38")
C:\Sites\ideas\gem_usage
37 mysh>ls
gem_latest.rb gem_usage.rb glmp.rb
C:\Sites\ideas\gem_usage
39 mysh>=require './glmp'
true
C:\Sites\ideas\gem_usage
40 mysh>=Gem.latest_version_for('gosu')
Gem::Version.new("0.14.4")
While I can use this hack to solve my problem for now, I think I will raise an issue with rubygems bringing up this matter.

Ohai thinks my plugin is version 6. Why?

I'm trying to write a plugin for ohai. It seems like a pretty straightforward task:
Ohai.plugin(:Uname) do
provides 'uname'
depends 'kernel'
collect_data do
uname Mash.new
uname[:message] = `uname -a`
end
end
To me this looks like the online examples provided by Opscode, O'Reilly and others. But here's what happens when I try to test it:
% irb -rohai
irb(main):001:0> Ohai::Config[:plugin_path] << "."
=> ["/home/ll0359/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/ohai-8.3.0/lib/ohai/plugins", "."]
irb(main):002:0> o = Ohai::System.new
=> #<Ohai::System:0x007fed82e43078 #plugin_path="", #data={}, #provides_map=#<Ohai::ProvidesMap:0x007fed82e42fd8 #map={}>, #v6_dependency_solver={}, #d82e42f38 #controller=#<Ohai::System:0x007fed82e43078 ...>, #v6_plugin_classes=[], #v7_plugin_classes=[]>, #runner=#<Ohai::Runner:0x007fed82e42ec0 #prp:0x007fed82e42fd8 #map={}>, #safe_run=true>>
irb(main):003:0> o.all_plugins
And here's where the fun begins. I get this output, over and over and over:
[2015-05-20T03:13:09+00:00] WARN: Plugin Definition Error: <./ohai_uname.rb>: collect_data already defined on platform default
[2015-05-20T03:13:09+00:00] WARN: [DEPRECATION] Plugin at ./test_ohai.rb is a version 6 plugin. Version 6 plugins will not be supported in future releases....
your plugin to version 7 plugin syntax. For more information visit here: docs.chef.io/ohai_custom.html
(the text on my second line was clipped by my screen but you get the idea)
I've tried running this code with and without the 'depends' line. Same result.
I've tried running this code with and without the Mash line, substituing 'uname uname -a' for the assignment line. Same result.
I've tried running with and without passing ":linux" as a parameter to collect_data. The only difference is I get a warning about collect_data(:linux) already being defined instead of :default.
I've tried renaming the plugin to a random 8 character identifier just in case it was tripping over being called :Uname. Same result.
I've tried passing "uname" (capital and lower) as a parameter to o.all_plugins. Same result.
So my questions are:
Why does ohai (8.3, running under Ruby 2.2.1) think this is a version 6 plugin? I can't see anything in it that would make it look like it's not version 7.
How can I get this working?
Thanks
Note to self: Next time you do this, don't try to test from the directory your plugin is in and add "." to your plugin_path. Moving to a different directory and adding the absolute path to the plugin solved the problem.
I plan to leave this up in case someone else has this happen to them.

Ruby/GSL online documentation for wrong version?

After successfuly installing Ruby/GSL library on my Debian (via *deb), with Ruby 1.9.3, I am having troubles running most of the GSL methods. Specifically, this webpage shows several code samples, but (in Arrays), right from the top line, require "GSL" is obsolete, it is require "gsl" today. The remaining methods also do not work.
For another example of my problem, consider another online reference to Ruby/GSL.
GSL::VERSION
#=> 1.15
GSL::pow_2( 4 )
#=> 16
But when I flip the page,
GSL::Complex.new( 0.9, 1.1 )
#=> ArgumentError: wrong number of arguments(2 for 0)
The simplest explanation to me would be that Ruby/GSL has more than one version hanging online, and the documentation I found is for the old one. For example, there is this abandoned version (https://github.com/codahale/ruby-gsl), so perhaps the version history is a bit complicated? Which is the authoritative version, and where can I finde the up-to-date documentation?
Following methods do work for the Complex module:
> c = GSL::Complex[0.9, 1.1]
=> GSL::Complex
[ 9.000e-01 1.100e+00 ]
> c.real
=> 0.9
> c.imag
=> 1.1
> c.pow 2
=> GSL::Complex
[ -4.000e-01 1.980e+00 ]

How to use ohai gem

In the OpsCode Wiki there is there following documentation:
require 'ohai'
# ...
# Profit! ;-)
How can I print the JSON data provided by the 'ohai' command but using IRB? I tried to see the code in application.rb but I get empty data.
require 'ohai/application'
ohai = Ohai::System.new
ohai.json_pretty_print
=> "{\n\n}"
I am not trying to do this within Chef (or Shef), I just want to use the ohai gem itself, in my own app.
Poking about in the Ohai::Application class (what you get when you run ohai), #run_application instantiates Ohai::System and, unless it was configured by a file, it calls all_plugins to populate it with data.
Presumably, Ohai::System#all_plugins delegates the data collection to the lib/ohai/plugins directory.
$ irb -rohai
> system = Ohai::System.new
=> #<Ohai::System:0x00000100988950 #data={}, #seen_plugins={}, #providers={}, #plugin_path="", #hints={}>
> system.all_plugins
=> true
> puts system.to_json
{"languages":{"ruby":{"platform":"x86_64-darwin10.8.0","version":"1.9.2", ...
> system.to_json.size
=> 42395
I too searched for a simple and good library to do that...
I came across
Usagewatch
and after 5 minutes had my monitoring.rb done..
Install : gem install usagewatch
Install on mac : gem install usagewatch_ext
Refer to this article for more info

Resources