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

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"

Related

What is the purpose of Ruby's unknown class?

I was looking through the Ruby Core API and noticed "unknown" at the bottom of the Classes list. When you go to that class's page at https://ruby-doc.org/core-2.6.1/unknown.html, you will notice that there is no content.
What is the purpose of this class, i.e. when and how would you use it? If there is no purpose, why is it documented on ruby-doc.org?
It looks like this is some kind of artifact of the documentation system and not an actual class in Ruby.
The documentation is produced by parsing the Ruby source code and can often get a little confused about what it's seeing. There's ways of coaching it with additional comments to ignore things it shouldn't document and so on, but tracking down which particular file or line produced this "unknown" reference is not necessarily easy.
You may want to report this as a bug in the documentation. That page isn't helpful, and is more confusing than anything.
There is no unknown class in Ruby. To prove #tadman's point simply run an IRB console:
irb(main):006:0> NilClass
=> NilClass
irb(main):007:0> Object
=> Object
irb(main):008:0> ZeroDivisionError
=> ZeroDivisionError
irb(main):009:0> Unknown
NameError: uninitialized constant Unknown
irb(main):010:0> unknown
NameError: undefined local variable or method `unknown' for main:Object

Ruby blank environment scope for execution

I'm currently developing a framework that basically executes another application, e.g. rails within the context of another ruby program. My initial attempt was simply to boot the app like this:
def load_app!
# Load the rails application
require './config/application'
# Initialize the rails application
#app = App::Application.initialize!
end
Problem here, is that the framework's requires conflict with the loaded application so the initialize! call never works although it would in a normal ruby program.
So my question is, if anyone knows a method to basically scope this calls into a unit that behaves like a blank RVM environment. So basically a behavior like this:
require 'json'
puts JSON.generate({:name => "test"})
blank_environment do
puts JSON.generate({:name => "test"})
#=> uninitialized constant JSON
require 'json'
puts JSON.generate({:name => "test"})
end
It's not done with undefining or unloading the currently loaded constants because I don't know all of them because I'm using gems that have other dependencies again.
So is there a cool way? Or any other way to handle this?
UPDATE:
Just came across an idea. Why is ruby's require method always requiring for the global scope? Wouldn't it be a very nice feature to actually scope the loaded modules under the the current module?
module ScopeA
require 'json' #> adds support for ScopeA::JSON
# due to normal ruby scoping everything can be called like normal in here
JSON.parse("something")
end
# JSON should not be available here
module ScopeB
require 'yaml'
YAML.parse("something") # but no JSON, of course
end
Doesn't something like this exist? include already has to know the constants...
Thanks in advance!
Well, after some more research it really doesn't seem possible the way I need it.
I now implemented a basic version using distributed ruby, which doesn't quite satisfy me:
require 'drb/drb'
URI = "druby://localhost:8787"
# Blank environment
pid = fork do
Signal.trap("INT") { puts "Stopping Server.."; exit }
class Application
def call(env)
[200,{},""]
end
end
DRb.start_service(URI, Application.new)
DRb.thread.join
end
# Working environment
DRb.start_service
app = DRbObject.new_with_uri(URI)
puts app.call({})
Process.kill("INT", pid)
Process.wait
If anyone comes up with a better approach, it's highly appreciated!

Kaminari and Capybara conflict

I seem to have some sort of conflict between the page method of capybara and the page method of Kaminari.
That's what I guessed, anyway, here is the error :
Failure/Error: before { sign_in_as user }
ActionView::Template::Error:
wrong number of arguments (1 for 0)
# ./app/models/feed.rb:9:in `microposts'
[Rest of the backtrace]
The code sample :
class Feed
def microposts(opts = { urgent: false })
urgent = opts[:urgent]
p Microposts.where(id: 1).page # <Capybara::Session>
p Microposts.where(id: 1).page(1) # Error
end
end
If I remove the pagination, the test works fine.
I don't understand how this is possible, I guess Capybara is adding the "page" method to the Object scope, but as Kaminari add its page method to ActiveRecord::Base (if I recall correctly) it should override Capybara's one.
I did not see anyone having this kind of trouble, how is it possible ?
Thanks.
I had the same problem with Capybara 2.x
My feature specs are in the spec/feature directory. I realised from reading the Capybara documentation that there is no need to include the Capybara::DSL in your spec_helper if your using the features directory. It's already included.
There is a warning given if you include Capybara::DSL in the spec_helper that it will pollute the global namespace and this is exactly why it's a bad idea!
Check out this rspec-rails page on Capybara for details
This is a little bit of a hack but I was able to work around the problem (where Capybara 'pollutes' the object space) by undef-ing the method in my spec:
# Capybara adds a 'page' method to the Object class which conflicts with the Kaminari scope
# Remove it here to allow things to work
Object.send :undef_method, :page
I have traced back where this is happening and essentially:
The #page method comes from Capybara::DSL
The Capybara::DSL method is included into the Object class via RSpec's #configure.include method (see lib/capybara/rspec.rb).
RSpec then includes it into the 'group', however I believe this is where it drops into Object.
The solution here might just be to change the name of the method in Capybara, but I guess thats not a decision I'm willing to make :)

can't load require_dependency

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'

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