Most appropriate place to require library in Padrino/Sinatra - ruby

I'm using "therubyracer" in a model, and I'm requiring at the top of the model as so:
require 'v8'
class Thing
def self.ctx; ##ctx ||= V8::Context.new; end;
def self.eval(script); ctx.eval(script); end;
end
However, I intermittently get:
NameError - uninitialized constant Thing::V8:
/app/thing.rb:3:in `ctx'
When testing requests through a local Padrino server, apparently after I modify code in Thing. This is corrected by restarting the padrino server. I'm assuming requiring v8 somewhere else would fix this problem, wheres the correct place?

This looks like it might be caused by the Padrino reloader getting confused when it reloads your thing.rb file, causing Ruby to look for V8 in the Thing namespace.
Try explicitly specifying V8 is in the top level using the :: prefix:
def self.ctx; ##ctx ||= ::V8::Context.new; end;

You can put it wherever you want if you add it on the Gemfile. Did you added it?
Thanks!

Related

Ruby: 'require' returns false even though file not loaded

I have this code:
puts require './item'
puts $"
class Light < Item
#code
end
Item class in item.rb:
require './v3d'
require './ray'
class Item
attr_accessor :pos
def initialize(pos)
#pos = pos
end
def check(pos, dir)
return nil
end
def normal(ray)
return nil
end
end
that when I run my program prints this output:
false
enumerator.so
thread.rb
rational.so
complex.so
/usr/lib/x86_64-linux-gnu/ruby/2.3.0/enc/encdb.so
/usr/lib/x86_64-linux-gnu/ruby/2.3.0/enc/trans/transdb.so
/usr/lib/ruby/2.3.0/unicode_normalize.rb
/usr/lib/x86_64-linux-gnu/ruby/2.3.0/rbconfig.rb
/usr/lib/ruby/2.3.0/rubygems/compatibility.rb
/usr/lib/ruby/2.3.0/rubygems/defaults.rb
/usr/lib/ruby/2.3.0/rubygems/deprecate.rb
/usr/lib/ruby/2.3.0/rubygems/errors.rb
/usr/lib/ruby/2.3.0/rubygems/version.rb
/usr/lib/ruby/2.3.0/rubygems/requirement.rb
/usr/lib/ruby/2.3.0/rubygems/platform.rb
/usr/lib/ruby/2.3.0/rubygems/basic_specification.rb
/usr/lib/ruby/2.3.0/rubygems/stub_specification.rb
/usr/lib/ruby/2.3.0/rubygems/util/list.rb
/usr/lib/x86_64-linux-gnu/ruby/2.3.0/stringio.so
/usr/lib/ruby/2.3.0/rubygems/specification.rb
/usr/lib/ruby/2.3.0/rubygems/exceptions.rb
/usr/lib/ruby/vendor_ruby/rubygems/defaults/operating_system.rb
/usr/lib/ruby/2.3.0/rubygems/core_ext/kernel_gem.rb
/usr/lib/ruby/2.3.0/monitor.rb
/usr/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb
/usr/lib/ruby/2.3.0/rubygems.rb
/usr/lib/ruby/vendor_ruby/did_you_mean/version.rb
/usr/lib/ruby/vendor_ruby/did_you_mean/core_ext/name_error.rb
/usr/lib/ruby/vendor_ruby/did_you_mean/levenshtein.rb
/usr/lib/ruby/vendor_ruby/did_you_mean/jaro_winkler.rb
/usr/lib/ruby/vendor_ruby/did_you_mean/spell_checkable.rb
/usr/lib/ruby/2.3.0/delegate.rb
/usr/lib/ruby/vendor_ruby/did_you_mean/spell_checkers/name_error_checkers/class_name_checker.rb
/usr/lib/ruby/vendor_ruby/did_you_mean/spell_checkers/name_error_checkers/variable_name_checker.rb
/usr/lib/ruby/vendor_ruby/did_you_mean/spell_checkers/name_error_checkers.rb
/usr/lib/ruby/vendor_ruby/did_you_mean/spell_checkers/method_name_checker.rb
/usr/lib/ruby/vendor_ruby/did_you_mean/spell_checkers/null_checker.rb
/usr/lib/ruby/vendor_ruby/did_you_mean/formatter.rb
/usr/lib/ruby/vendor_ruby/did_you_mean.rb
/home/<user>/Documents/ruby/ray/write_ppm.rb
/home/<user>/Documents/ruby/ray/v3d.rb
/home/<user>/Documents/ruby/ray/pixel.rb
/home/<user>/Documents/ruby/ray/image.rb
/home/<user>/Documents/ruby/ray/material.rb
then throws:
/home/<user>/Documents/ruby/ray/light.rb:4:in `<top (required)>': uninitialized constant Item (NameError)
When require './item' is called, there is no error AND it returns false. From my understanding of how require works, it seems that the program incorrectly thinks it does not need to load item.rb. Why does this happen and how can I fix it?
Edit: expanded on some code
As a generic answer, not related to op, but because I had a similar issue and was pointed here by search engines.
Basically require 'http' returned false while gem was not loaded.
I figured out that there is a http.rb file inside load path and it is being loaded instead of the standard gem. So double check there are no conflicting file names of ruby files under library load path and the gem name.
I solved the problem by totally rewriting my require statements for every file. What I think the problem was, was this:
item.rb contained require './ray'
ray.rb contained require './light'
light.rb contained require './item' and class Light < Item
While loading item.rb, the interpreter saw it needed to also load ray.rb and therefore light.rb. When it reached the require './item' inside light.rb, it returned false because it was in the process of loading that file. However, since it was not yet finished loading, it did not show up in $". The interpreter then needed access to the definition of the Item class to finish loading light.rb, but because it needed to finish loading light.rb to load item.rb, the interpreter thew a NameError.
I think you may want require_relative instead.
http://ruby-doc.org/core-2.4.0/Kernel.html#method-i-require_relative
vs
http://ruby-doc.org/core-2.4.0/Kernel.html#method-i-require
You are correct in saying that if require 'my_lib' returns false, then 'my_lib' has already been loaded. However this is different from saying that a MyLib class is defined. Does your item.rb define an Item class?
Also, it may be possible that Item is defined somewhere else in the namespace hierarchy. e.g. if your item.rb is in some_gem/item.rb, and you're calling require from some_gem/, it will load successfully, but the name of the class might be SomeGem::Item. In this case you wouldn't be able to access it directly from the root namespace.
Last thing I can think of is that the item.rb file is changing under, or otherwise has some very dynamic pieces that are confusing the interpreter.
I would think that the issue is one of these before thinking that require is somehow messing up.

Attempting to use pools crashes Celluloid

I'm trying to use pools in a project of mine that uses Celluloid. However, whenever I invoke the pool method on a class which includes Celluloid (thus receiving methods from Celluloid::ClassMethods) I consistently get the error:
NoMethodError: undefined method `services' for Celluloid:Module
router at /Users/my_username/.rvm/gems/jruby-9.0.5.0/gems/celluloid-supervision-0.20.6/lib/celluloid/supervision/deprecate/supervise.rb:54
supervise at /Users/my_username/.rvm/gems/jruby-9.0.5.0/gems/celluloid-supervision-0.20.6/lib/celluloid/supervision/deprecate/supervise.rb:6
pool at /Users/my_username/.rvm/gems/jruby-9.0.5.0/gems/celluloid-pool-0.20.5/lib/celluloid/supervision/container/behavior/pool.rb:13
<top> at celluloid_pool_test.rb:14
Specifically, this part seems to be the problem:
NoMethodError: undefined method `services' for Celluloid:Module
It tells me that the offending line is /Users/my_username/.rvm/gems/jruby-9.0.5.0/gems/celluloid-supervision-0.20.6/lib/celluloid/supervision/deprecate/supervise.rb:54. It turns out that line holds the code for the Celluloid::Supervision.router method:
def router(*_args)
# TODO: Actually route, based on :branch, if present; or else:
Celluloid.services ### this line is what causes the error
end
To make sure that the issue wasn't with my particular project, I grabbed a code sample from this article which utilizes pools and tried to run it:
require 'celluloid'
require 'mathn'
class PrimeWorker
include Celluloid
def prime(number)
if number.prime?
puts number
end
end
end
pool = PrimeWorker.pool
(2..1000).to_a.map do |i|
pool.prime! i
end
sleep 100
It failed with the exact same error as my project:
Finally, I ran a dead simple piece of code in IRB to see if pool is what triggers the error about services:
class Foo
include Celluloid
end
Foo.pool
Sure enough, I got the exact same error. It seems that there is a bug in Celluloid or that I'm not loading a dependency properly. However, I did require 'celluloid/supervision' in my attempts at solving this, to no avail. Am I doing something wrong on my end or is this a bug in Celluloid?
It seems that others have run into this issue before: https://github.com/celluloid/celluloid-pool/issues/10. I guess it has something to do with Celluloid.services being deprecated and not working in newer versions of Celluloid, so using require 'celluloid/current' rather than just require 'celluloid' seems to do the trick.

How can I run a method at the end of a file from a gem?

I have a gem (e.g. mygem) and as is normal, I add mygem to a file by putting require "mygem" at the top. What if I have a method in mygem called finish_jobs and I want it to run in the following location:
require "mygem"
# code, code code
finish_jobs
How would I do that without forcing the user to add the method every time they use the gem?
Specifically, what I am trying to do is write a server app (with rack) and I need the methods in the body of the file to be processed before the server is started.
This is certainly possible.
Why not just add the code directly into the Gem (since it sounds like it is under your control and is not an external dependency)?
module MyGem
def printSomething
p 2 + 2
end
module_function :printSomething
printSomething()
# => 4
end
If this isn't what you had in mind, let me know and I can update the solution.
Also, see Kernel#at_exit
A more explanatory guide on Kernel#at_exit
I don't know of a way to do what you're describing.
One workaround would be to provide an API which accepts a block. This approach allows you to run code after the user's setup without exposing implementation details to them.
A user could call your library method, providing a block to set up their server:
require "mygem"
MyGem.code_code_code {
# user's code goes here
}
Then, your library code would:
Accept the block
Call some library code
Here's an example implementation:
module MyGem
# Run some user-provided code by `yield`-ing the block
# Then run the gem's finalizer
def self.code_code_code
# Execute the block:
yield
# Finalize:
finish_jobs
end
end
This way, you can accept code from the user but still control setup and finalization.
I hope it helps!

How to create a sandboxed RSpec environment?

Essentially, I want to create a program that will run some untrusted code that defines some method or class, and then run an untrusted rspec spec against it.
I've looked into sandboxing Ruby a bit, and this video from rubyconf was particularly helpful. After looking at several solutions, the two that appear to be the most helpful are rubycop, which essentially does static analysis on the code, and the jruby sandbox (both covered in above video). My instinct tells me that the jruby sandbox is probably safer, but I could well be wrong.
Here's a completely unsafe example of what I want to do:
code = <<-RUBY
class Person
def hey
"hey!"
end
end
RUBY
spec = <<-RUBY
describe Person do
let(:person) { Person.new }
it "says hey" do
person.hey.should == "hey!"
end
end
RUBY
# code and spec will be from user input (unsafe)
eval code
require 'rspec/autorun'
eval spec
Which all works fine, but the code obviously needs to be sandboxed. It will be a matter of minutes before some genius submits system("rm -rf /*"), fork while fork or something equally dangerous.
I made various attempts with the jruby sandbox...
sand = Sandbox::Safe.new
sand.eval("require 'rspec/autorun'")
sand.activate! # lock it down
sand.eval code
puts sand.eval spec
That code throws this exception:
Sandbox::SandboxException: NoMethodError: undefined method `require' for #<RSpec::Core::Configuration:0x7c3cfaab>
This is because RSpec tries to require some stuff after the sandbox has been locked down.
So, I tried to force RSpec to require stuff before the sandbox gets locked down by calling an empty describe:
sand = Sandbox::Safe.new
sand.eval("require 'rspec/autorun'")
sand.eval("describe("") { }")
sand.activate! # lock it down
sand.eval code
sand.eval spec
And I get this:
Sandbox::SandboxException: NameError: uninitialized constant RSpec
Which basically means that RSpec doesn't exist in the sandbox. Which is odd, considering sand.eval("require 'rspec/autorun'") returns true, and that the earlier example actually worked (RSpec's autoloader started to run).
It may be a problem with gems and this particular sandbox though. The sandbox object actually supports a method #require, which is essentially bound to Kernel.require, and therefore can't load gems.
It's starting to look like using this sandbox just might not really be possible with rspec. The main problem is trying to actually load it into the sandbox. I even tried something like this:
require 'rspec'
sand.ref(RSpec) # open access to local rspec
But it wasn't having any of it.
So, my question is two-fold:
Does anyone have any bright ideas on how to get this to work with the jruby sandbox?
If not, how secure is rubycop? Apparently codeschool use it, so it must be pretty well tested... it would be nice to be able to use ruby 1.9 instead of jruby as well.
It looks like the sand box environment isn't loading the bundle/gemset. RVM could be at fault here if you are using a gemset or something.
One might try loading the Bundle again once sand boxed.
I would look at ruby taint modes
$SAFE The security level
0 --> No checks are performed on externally supplied (tainted) data. (default)
1 --> Potentially dangerous operations using tainted data are forbidden.
2 --> Potentially dangerous operations on processes and files are forbidden.
3 --> All newly created objects are considered tainted.
4 --> Modification of global data is forbidden.
I have been trying to figure out a similar problem. I want to use some gems like json and rest-client inside my sandbox after activating it. I tried following.
require "sandbox"
s=Sandbox.safe
s.eval <<-RUBY
require 'bundler'
Bundler.require :sandbox
RUBY
s.activate!
Gemfile.rb
group :sandbox do
platforms :jruby do
gem 'json'
gem 'rest-client'
end
end
This way, I was able to require gems in my sandbox. But, then there were some gem specific issues with sandbox. For eg, I had to add a method initialize_dup to whitelist for safe.rb in jruby-sandbox. RestClient has some problem with Fake File Sytem ALT_SEPARATOR which I am trying to patch. You can try this approach for RSpec and see if everything goes through.

Requiring gem in Rails 3 Controller failing with "Constant Missing"

I've seen this asked a few times in other threads, but none of the answers seem to apply.
Environment:
Rails 3
amazon/ecs gem from jugend. The lone file is here:
http://github.com/jugend/amazon-ecs/blob/master/lib/amazon/ecs.rb
my gemfile has:
gem 'amazon-ecs', :git => 'git://github.com/jugend/amazon-ecs.git'
Everything works in irb. I can run:
bundle console
require 'amazon/ecs' and then go to town
when I try to use it from the controller though, like so:
require 'amazon/ecs'
require 'amazon/ecs'
class SearchController < ApplicationController
def index
end
def results
Amazon::Ecs.configure do |options|
options[:aWS_access_key_id] = '[key]'
options[:aWS_secret_key] = '[secret]'
end
res = Amazon::Ecs.item_search(params[:search], {:response_group => 'Medium', :search_index => 'All'})
end
end
I get: uninitialized constant SearchController::Amazon at line 8, where I first try to use Amazon.
the ecs.rb has a module Amazon containing a class Ecs. I'm not sure why this is working in erb, and not in rails.
I'm still kinda new to Rails, so please answer using small words. :-/
Was given the answer. I moved my initialization code to an initializer in config/initializers file, removed the require entirely, and things worked. I don't know why though, so if someone could answer that, that'd be great.
All of the gems require their files by default, so usually you don't need to explicitly require any files.
Speaking about your problem, it could somehow be, that your controller is run before Amazon module is processed.

Resources