lib/formtastic/helpers/input_helper.rb in formtastic-3.0.0 vs lib/formtastic/helpers/input_helper.rb in formtastic-3.1.0.rc1

- old
+ new

@@ -34,10 +34,13 @@ # # @see #input # @see Formtastic::Helpers::InputsHelper#inputs # @see Formtastic::Helpers::FormHelper#semantic_form_for module InputHelper + INPUT_CLASS_DEPRECATION = 'configure Formtastic::FormBuilder.input_class_finder instead'.freeze + private_constant(:INPUT_CLASS_DEPRECATION) + include Formtastic::Helpers::Reflection include Formtastic::Helpers::FileColumnDetection # Returns a chunk of HTML markup for a given `method` on the form object, wrapped in # an `<li>` wrapper tag with appropriate `class` and `id` attribute hooks for CSS and JS. @@ -84,30 +87,30 @@ # defined in a module of the same name. Detailed documentation for each input style and it's # supported options is available on the `*_input` method in each module (links provided below). # # Available input styles: # - # * `:boolean` (see {Inputs::BooleanInput}) - # * `:check_boxes` (see {Inputs::CheckBoxesInput}) - # * `:color` (see {Inputs::ColorInput}) - # * `:country` (see {Inputs::CountryInput}) - # * `:datetime_select` (see {Inputs::DatetimeSelectInput}) - # * `:date_select` (see {Inputs::DateSelectInput}) - # * `:email` (see {Inputs::EmailInput}) - # * `:file` (see {Inputs::FileInput}) - # * `:hidden` (see {Inputs::HiddenInput}) - # * `:number` (see {Inputs::NumberInput}) - # * `:password` (see {Inputs::PasswordInput}) - # * `:phone` (see {Inputs::PhoneInput}) - # * `:radio` (see {Inputs::RadioInput}) - # * `:search` (see {Inputs::SearchInput}) - # * `:select` (see {Inputs::SelectInput}) - # * `:string` (see {Inputs::StringInput}) - # * `:text` (see {Inputs::TextInput}) - # * `:time_zone` (see {Inputs::TimeZoneInput}) - # * `:time_select` (see {Inputs::TimeSelectInput}) - # * `:url` (see {Inputs::UrlInput}) + # * `:boolean` (see {Inputs::BooleanInput}) + # * `:check_boxes` (see {Inputs::CheckBoxesInput}) + # * `:color` (see {Inputs::ColorInput}) + # * `:country` (see {Inputs::CountryInput}) + # * `:datetime_select` (see {Inputs::DatetimeSelectInput}) + # * `:date_select` (see {Inputs::DateSelectInput}) + # * `:email` (see {Inputs::EmailInput}) + # * `:file` (see {Inputs::FileInput}) + # * `:hidden` (see {Inputs::HiddenInput}) + # * `:number` (see {Inputs::NumberInput}) + # * `:password` (see {Inputs::PasswordInput}) + # * `:phone` (see {Inputs::PhoneInput}) + # * `:radio` (see {Inputs::RadioInput}) + # * `:search` (see {Inputs::SearchInput}) + # * `:select` (see {Inputs::SelectInput}) + # * `:string` (see {Inputs::StringInput}) + # * `:text` (see {Inputs::TextInput}) + # * `:time_zone` (see {Inputs::TimeZoneInput}) + # * `:time_select` (see {Inputs::TimeSelectInput}) + # * `:url` (see {Inputs::UrlInput}) # # Calling `:as => :string` (for example) will call `#to_html` on a new instance of # `Formtastic::Inputs::StringInput`. Before this, Formtastic will try to instantiate a top-level # namespace StringInput, meaning you can subclass and modify `Formtastic::Inputs::StringInput` # in `app/inputs/`. This also means you can create your own new input types in `app/inputs/`. @@ -231,11 +234,11 @@ # last_name: "Smith" # # @todo Many many more examples. Some of the detail probably needs to be pushed out to the relevant methods too. # @todo More i18n examples. def input(method, options = {}) - method = method.to_sym if method.is_a?(String) + method = method.to_sym options = options.dup # Allow options to be shared without being tainted by Formtastic options[:as] ||= default_input_type(method, options) klass = input_class(options[:as]) @@ -297,19 +300,25 @@ end end # Get a column object for a specified attribute method - if possible. def column_for(method) #:nodoc: - @object.column_for_attribute(method) if @object.respond_to?(:column_for_attribute) + if @object.respond_to?(:column_for_attribute) + # Remove deprecation wrapper & review after Rails 5.0 ships + ActiveSupport::Deprecation.silence do + @object.column_for_attribute(method) + end + end end - # Takes the `:as` option and attempts to return the corresponding input class. In the case of - # `:as => :string` it will first attempt to find a top level `StringInput` class (to allow the - # application to subclass and modify to suit), falling back to `Formtastic::Inputs::StringInput`. + # Takes the `:as` option and attempts to return the corresponding input + # class. In the case of `:as => :awesome` it will first attempt to find a + # top level `AwesomeInput` class (to allow the application to subclass + # and modify to suit), falling back to `Formtastic::Inputs::AwesomeInput`. # - # This also means that the application can define it's own custom inputs in the top level - # namespace (eg `DatepickerInput`). + # Custom input namespaces to look into can be configured via the + # .input_namespaces +FormBuilder+ configuration setting. # # @param [Symbol] as A symbol representing the type of input to render # @raise [Formtastic::UnknownInputError] An appropriate input class could not be found # @return [Class] An input class constant # @@ -317,33 +326,51 @@ # input_class(:string) #=> Formtastic::Inputs::StringInput # input_class(:date) #=> Formtastic::Inputs::DateInput # # @example When a top-level class is found # input_class(:string) #=> StringInput - # input_class(:awesome) #=> AwesomeInput + # input_class(:awesome) #=> AwesomeInput + + def namespaced_input_class(as) + @input_class_finder ||= input_class_finder.new(self) + @input_class_finder.find(as) + rescue Formtastic::InputClassFinder::NotFoundError + raise Formtastic::UnknownInputError, "Unable to find input #{$!.message}" + end + + # @api private + # @deprecated Use {#namespaced_input_class} instead. def input_class(as) + return namespaced_input_class(as) if input_class_finder + + input_class_deprecation_warning(__method__) + @input_classes_cache ||= {} @input_classes_cache[as] ||= begin config = Rails.application.config use_const_defined = config.respond_to?(:eager_load) ? config.eager_load : config.cache_classes use_const_defined ? input_class_with_const_defined(as) : input_class_by_trying(as) end end - + + # @api private + # @deprecated Use {InputClassFinder#find} instead. # prevent exceptions in production environment for better performance def input_class_with_const_defined(as) input_class_name = custom_input_class_name(as) if ::Object.const_defined?(input_class_name) input_class_name.constantize elsif Formtastic::Inputs.const_defined?(input_class_name) - standard_input_class_name(as).constantize + standard_input_class_name(as).constantize else raise Formtastic::UnknownInputError, "Unable to find input class #{input_class_name}" end end - + + # @api private + # @deprecated Use {InputClassFinder#find} instead. # use auto-loading in development environment def input_class_by_trying(as) begin custom_input_class_name(as).constantize rescue NameError @@ -351,17 +378,30 @@ end rescue NameError raise Formtastic::UnknownInputError, "Unable to find input class for #{as}" end + # @api private + # @deprecated Use {InputClassFinder#class_name} instead. # :as => :string # => StringInput def custom_input_class_name(as) + input_class_deprecation_warning(__method__) "#{as.to_s.camelize}Input" end + # @api private + # @deprecated Use {InputClassFinder#class_name} instead. # :as => :string # => Formtastic::Inputs::StringInput def standard_input_class_name(as) + input_class_deprecation_warning(__method__) "Formtastic::Inputs::#{as.to_s.camelize}Input" + end + + private + + def input_class_deprecation_warning(method) + @input_class_deprecation_warned ||= + Formtastic.deprecation.deprecation_warning(method, INPUT_CLASS_DEPRECATION, caller(2)) end end end end