can't load require_dependency - ruby

I'm trying to use require_dependency from ActiveSupport library in pry:
require 'active_support' #=> true
require_dependency 'test' #=> NoMethodError: undefined method
#=> `require_dependency' for main:Object
What could be the problem?

ActiveSupport used to be pretty evil by loading a ton of stuff on require. The "kitchen sink" approach opened a lot of core classes up and changed their behavior (like JSON). This caused incompatibilities/problems with other gems and code that expected core ruby functions to behave like their vanilla selves.
So now requiring just active_support does not load anything.
see http://edgeguides.rubyonrails.org/active_support_core_extensions.html
in your case you probably will need require 'active_support/core_ext'

Related

How does require always load into the top-level scope?

Consider this Ruby code:
class A
require 'json'
end
Because Ruby is interpreted and executes code line-by-line, I would expect JSON to be scoped inside A.
However:
irb(main):005:0> A::JSON
Traceback (most recent call last):
4: from /usr/bin/irb:23:in `<main>'
3: from /usr/bin/irb:23:in `load'
2: from /usr/lib/ruby/gems/2.7.0/gems/irb-1.2.1/exe/irb:11:in `<top (required)>'
1: from (irb):5
NameError (uninitialized constant A::JSON)
irb(main):004:0> JSON
=> JSON
How does require always load gems into the top-level scope?
require is implemented inside the VM, so it has access to internal functionality that normal Ruby code does not. For example it can manually escape its current scope and execute code at the top level. That is "how".
As for "why"? Imagining if you could require into a specific scope, this would be extremely prone to breakage since it would change top-level self from main (which is an Object) to... anything (in your example it would be A, which is a Class). It would be very hard to predict in general what would happen when your code is required.
By always executing loaded code at the top-level, the result is always consistent. And you can use the built-in hook mechanisms (included, extended, prepended, inherited) to access specific selfs from the scope that loaded you.

Error uninitialized constant with a class inheritance

Clearly there is something off with how I understand it in ruby. I have 3 ruby files main, base, and derived. I have two classes Derived specializes from Base.
/bin/main.rb
require './lib/base'
/lib/base.rb
require './lib/derived'
class Base
end
/lib/derived.rb
require './lib/base'
class Derived < Base
end
running with rake ruby './bin/main.rb'
`<top (required)>': uninitialized constant Base (NameError)
What is causing the error?
Edit:
I just realized one point I was missing was that I forgot that require is a Kernel#method, that I do not need to keep on top of my code every time like I normally do with other languages.
The issue here is that the require './lib/derived' in the /lib/base.rb file is actually causing /lib/derived.rb to be parsed before Base is declared in /lib/base.rb. Try this, instead:
/bin/main.rb
require './lib/base'
require './lib/derived'
puts 'Success!'
/lib/base.rb
class Base
end
/lib/derived.rb
require './lib/base'
class Derived < Base
end
This allows the declarations to occur in the proper order.
As a side note, it isn't technically necessary to require './lib/base' in lib/main.rb, since it's actually successfully included in lib/derived.rb, but it is good form if Base is used directly in the body of lib/main.rb.

Rails: How do I require NumberHelper and make it work?

I'm trying to write a simple Sinatra thingy but I need ActionView::Helpers::NumberHelper from action pack.
http://api.rubyonrails.org/classes/ActionView/Helpers/NumberHelper.html
The question is, how do I install and use it?
irb(main):001:0> require 'action_view/helpers/number_helper'
irb(main):002:0> number_with_precision(1)
NoMethodError: undefined method `number_with_precision' for main:Object
irb(main):004:0> ActionView::Helpers::NumberHelper.number_with_precision(1)
NoMethodError: undefined method `number_with_precision' for ActionView::Helpers::NumberHelper:Module
Why doesn't this simple step work?
Moreover, if I require all the crap:
irb(main):001:0> require 'action_pack'
irb(main):004:0> require 'action_view'
irb(main):005:0> include ActionView::Helpers::NumberHelper
irb(main):006:0> number_to_phone(12345)
NoMethodError: undefined method `starts_with?' for "12345":String
How to make sense from all of this? Why does not this module work? Why doesn't it require whatever it needs? What does it need? Where is starts_with?
Google is utterly silent on those questions.
UPD: And now I get the following
number_with_precision(1, :locale => 'fr')
TypeError: wrong argument type nil (expected Fixnum)
It seems to me that my NumberHelper is broken. This isn't a good behavior.
So, after doing a bit of research, I found the following pull request on the master branch of Rails
https://github.com/rails/rails/pull/6315
It pretty much aims to move ActionView::Helpers::NumberHelper from ActionView to ActiveSupport
I also saw a few closed issues that aimed to fix a few problems with allowing inclusion of NumberHelper as standalone. This means require fixes and such. I didn't find an open issue with the number_to_phone but the problem roots at the fact that ActiveSupport adds an alias starts_with? to the String class. I'm not sure if they have caught that bug there yet or not.
In any case, with ActionView version 3.2.13 you can do the following
require 'action_view'
include ActionView::Helpers::NumberHelper
number_with_precision 3.1
#=> "3.100"
As for the number_to_phone, that will still break with the current version. I'm making a PR to fix that issue at this moment.
EDIT
As for the locale issue, it seems that if you specify a local you need to have set the right options in the I18n for it to work. If you don't provide a locale the defaults will look like this {:separator=>".", :delimiter=>"", :precision=>3, :significant=>false, :strip_insignificant_zeros=>false}, otherwise, the hash will be empty and it will cause issues. I can't seem to find any issues about it on Rails though.
Again, this was fixed on a PR on master https://github.com/carlosantoniodasilva/rails/commit/f6b71499e967e03c65d53cc890585f42f3b8aaa2
UPDATE
You can use ActiveSupport now to use these helpers
http://api.rubyonrails.org/classes/ActiveSupport/NumberHelper.html
It changed recently:
require "active_support/all"
module Helpers
extend ActiveSupport::NumberHelper
end
Helpers.number_to_currency(10.23) # => "$10.23"

Ruby Gem with Acroynym in the name

[SOLVED: See my comment below]
I've created a Ruby Gem to connect to my application's API: my_app_api. I'd like to use it like so: MyAppAPI::Foo.bar(). However, I get:
NameError: uninitialized constant MyAppAPI
I know the standard way to call/name this would be MyAppApi::Foo.bar(), but I'd prefer to keep with acronym class naming conventions. How do I specify/load the module?
For reference, the class looks like this:
module MyAppAPI
class Foo < ActiveResource::Base
extend MyAppAPI
self.site = 'http://localhost:3000/api/'
self.format = :json
class << self
def bar
return 'huzzah!'
end
end
end
end
And the my_app_api.rb file looks like this:
require "rubygems"
require 'active_resource'
require 'my_app_api/foo'
Have you tried loading the gem the normal way?
require 'my_app_api'
MyAppAPI::Foo.bar()
The constant name MyAppAPI is fine and is not the cause of the problem. There are tons of Ruby core classes/modules that have acronyms in their names:
http://www.ruby-doc.org/core-1.9.3/GC.html
http://www.ruby-doc.org/core-1.9.3/RubyVM.html
http://ruby-doc.org/stdlib-1.9.3/libdoc/csv/rdoc/CSV.html
Try declaring the empty module in my_app_api.rb after your require statements:
module MyAppAPI
end
This may help if you're relying on a dynamic class and module loading mechanism (like Rails uses).
I assume your app is explicitly calling require "my_app_api". What kind of app is this, and where are you doing the require?

Getting methods into plain file dynamically in Ruby

I've noticed in some gems, when you simply require 'some_gem', methods will appear (without any monkey patching to my knowledge). I've seen it in some gems like Sinatra, Rake, Rails, and many other helper libraries and such. How would one manage to accomplish this in ones own library?
Example:
require 'sinatra'
# Automatically recieve the 'get' method
get('/') { "I was monkeypatched or included automatically." }
If it is monkeypatching, what classes/modules are common for monkeypatching (other than String, Numeric, Array, etc).
Sinatra is essentially adding those as global methods. When you require sinatra, it extends the Object class with Sinatra::Delegator which is defined in sinatra/base.rb. Methods such as get and put are defined in base, and added via the delegator.
In addition to Beerlington's answer, Rails, for example, and specifically it's part ActiveSupport, uses exactly monkeypatching.
For example, declaration of blank? method from the ActiveSupport source (stripped):
class Object
def blank?
respond_to?(:empty?) ? empty? : !self
end
end
Also, very common approach to monkeypatch Kernel module to add methods that will be available everywhere:
# hello.rb
module Kernel
def say_hello
"Hello!"
end
end
And usage of it:
require 'hello.rb'
=> true
say_hello
=> "Hello!"

Resources