At least, now that I know that this behavior is intentional in Rails I documented myself in my own class so that other developers could also understand the reason I'm depending on full ActionView when I really depend only on NumberHelper:

require 'bigdecimal'
# In Rails, if you need action_view/helpers/number_helper you have to require 'action_view', # then 'action_view/helpers and finally 'action_view/helpers/number_helper'. Pretty stupid but we don't control # Rails. Since ActionView will load all components, we don't need to require the other files, just 'action_view':
require 'action_view'
#require 'action_view/helpers/number_helper'


Em 08-02-2013 15:53, Rodrigo Rosenfeld Rosas escreveu:
Is this documented somewhere? Since it doesn't follow any best practices I think this particular Rails behavior should be documented, right?

Em 08-02-2013 15:51, Rafael Mendonça França escreveu:
The correct way to use any one of the rails pieces is to require the framework file first.

You have to do

|require  'action_view'  # this file only loads what is needed to use the 
framework inside and outside the rails scope
require  'action_view/helpers'|

Rafael Mendonça França
http://twitter.com/rafaelfranca
https://github.com/rafaelfranca


On Fri, Feb 8, 2013 at 3:46 PM, Rodrigo Rosenfeld Rosas <[email protected] <mailto:[email protected]>> wrote:

    I know it is tangential. I was just explaining why I don't agree
    with the current approach because non Rails code could rely only
    on 'action_view/helpers', don't you agree? How are they supposed
    to know that they should first require 'active_support/rails' or
    any other entry point?

    I don't think it is fine to just assume that ActionView classes
    only make sense in within the Rails context. This is an unsafe
    assumption that I don't agree with.

    Em 08-02-2013 15:42, Xavier Noria escreveu:
    I am only explaining why autoload and concern have no explicit
    requires in that file. That was a tangential question you did
    not directly related to the exception.

    Sent from my iPhone

    On 08/02/2013, at 18:36, Rodrigo Rosenfeld Rosas
    <[email protected] <mailto:[email protected]>> wrote:

    I don't understand what you mean. In my unit tests involving
    ParseFormatUtils for instance Rails is never loaded and my
    application doesn't even use ActiveRecord.

    But my tests weren't complaining anyway because they don't
    autoload ActionView/Helpers.

    Also, even if I explicitly required as/rails it wouldn't fix
    the situation for my case.

    This is what's happening in a simplified way:


    ./test.rb:
    autoload :A, 'a'
    require 'a/b'

    ./lib/a.rb:
    module A
      autoload :B, 'a/b'
      include B
    end

    ./lib/a/b.rb:
    module A
      module B
      end
    end

    ruby -I lib test.rb


    This is enough to create the circular dependency error. Maybe
    this is one of the reasons why Matz wants to remove autoload
    from Ruby...

    Sorry but I don't have any suggestions right now that would
    make require 'a/b' work if 'a' is set to be autoloaded and 'a'
    requires 'b' which depends on 'a'...

    Unless we create some 'action_view/helpers/all.rb'  file. Would
    that be acceptable?

    Best,
    Rodrigo.

    Em 08-02-2013 15:26, Xavier Noria escreveu:
    No, no, as/rails.rb is already required by the entry point
    of every component (except AS). That is a given in the
    context of a Rails application, and

        gem 'active_record'

    does that if standalone.

    Sent from my iPhone

    On 08/02/2013, at 18:12, Rodrigo Rosenfeld Rosas
    <[email protected] <mailto:[email protected]>> wrote:

    Em 08-02-2013 15:00, Xavier Noria escreveu:
    Some very common files are loaded at the entry point of
    every component, to avoid repeating their require again and
    again:

    
https://github.com/rails/rails/blob/master/activesupport/lib/active_support/rails.rb

    But shouldn't helpers.rb require 'active_support/rails' then
    instead of just 'active_support/benchmarkable'?

    Otherwise it should be documented that we're not supposed to
    require specific parts of some libraries included in Rails...
    That way I'd know (although surprised) that I'm not supposed
    to require 'action_view/helpers/number_helper' but simply
    'action_view/helpers' (or just 'action_view'?)


    As for the autoload + include, I don't really know, maybe it
    is a fancy way to avoid writing a file path. Seems
    unnecessary to me at first glance. Maybe someone else from
    the team has a better justification?

    Sent from my iPhone

    On 08/02/2013, at 17:45, Rodrigo Rosenfeld Rosas
    <[email protected] <mailto:[email protected]>> wrote:

    Em 08-02-2013 13:03, Xavier Noria escreveu:
    On Fri, Feb 8, 2013 at 3:18 PM, Rodrigo Rosenfeld Rosas
    <[email protected]>  <mailto:[email protected]>  wrote:

    Em 08-02-2013 12:06, Xavier Noria escreveu:

    Seems unrelated to dependencies.rb, most likely a missing require
    somewhere within Rails.

    It can be the case that it does not show up in production because of eager
    loading.
    Any ideas why helpers.rb is loaded when you write code like below?

    module ActionView
       module Helpers
         module NumberHelper

    Is this normal MRI behavior or is this caused by dependencies.rb?
    Ruby on Rails itself does not use dependencies.rb to load its code. It
    is a regular Ruby library that uses requires and Kernel#autoload with
    some added sugar. AS::Dependencies only covers application constant
    autoloading.

    The thing goes like this: When an application boots in any environment
    action_view.rb is loaded. When that file is executed an autoload for
    :Helpers is configured under ActionView. In a default setup,
    helpers.rb is not yet loaded. That is, if you run

         rails runner 1

    helpers.rb is not loaded (at least in 3-2-stable, not that we are
    explaining any contract, only load order execution to follow what
    happens in your exception).

    But if you force the evaluation of the constant as in your example above:

         module ActionView
           module Helpers
             ...
           end
         end

    that autoload is triggered because the interpreter checks whether
    "Helpers" is a constant defined in the module object stored in
    ActionView. Therefore, helpers.rb is interpreted and sets in turn an
    autoload for NumberHelper below AV::Helpers.

    So, module Helpers in that snippet *reopens* a module object defined
    via the autoload, rather than creating the module object. The
    execution follows and the same happens with the "NumberHelper"
    constant down below. The interpreter checks whether it belongs to the
    module object stored in AV::Helpers. Since it is unknown and there is
    an autoload for it it gets triggered, and loads... well the very
    number_helper.rb whose execution we were in the middle of (not sure
    this sentence is valid English :).

    I suspect there is a circularity here that is showing up that way.

    Would need to dig deeper to fully explain how this ends up in an
    exception, maybe I'll do it tonight, but in the meantime here's some
    context in case it helps.

    It makes total sense. What doesn't make sense is the source
    of helpers.rb to me:

    
https://github.com/rails/rails/blob/master/actionpack/lib/action_view/helpers.rb

    First it should explicitly require (or require_dependency)
    'active_support/autoload' and 'active_support/concern', right?

    But then, why using autoload if you're just including all
    modules next?




--
You received this message because you are subscribed to the Google Groups "Ruby on 
Rails: Core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to