diff options
Diffstat (limited to 'actionpack/lib/action_view')
-rw-r--r-- | actionpack/lib/action_view/helpers/date_helper.rb | 34 | ||||
-rw-r--r-- | actionpack/lib/action_view/locale/en.yml | 3 | ||||
-rw-r--r-- | actionpack/lib/action_view/render/rendering.rb | 5 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/error.rb | 2 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/handlers/builder.rb | 2 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/template.rb | 119 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/text.rb | 29 | ||||
-rw-r--r-- | actionpack/lib/action_view/test_case.rb | 125 |
8 files changed, 215 insertions, 104 deletions
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb index 332743d55b..8a7a870b99 100644 --- a/actionpack/lib/action_view/helpers/date_helper.rb +++ b/actionpack/lib/action_view/helpers/date_helper.rb @@ -26,8 +26,10 @@ module ActionView # 47 hrs, 59 mins, 29 secs <-> 29 days, 23 hrs, 59 mins, 29 secs # => [2..29] days # 29 days, 23 hrs, 59 mins, 30 secs <-> 59 days, 23 hrs, 59 mins, 29 secs # => about 1 month # 59 days, 23 hrs, 59 mins, 30 secs <-> 1 yr minus 1 sec # => [2..12] months - # 1 yr <-> 2 yrs minus 1 secs # => about 1 year - # 2 yrs <-> max time or date # => over [2..X] years + # 1 yr <-> 1 yr, 3 months # => about 1 year + # 1 yr, 3 months <-> 1 yr, 9 months # => over 1 year + # 1 yr, 9 months <-> 2 yr minus 1 sec # => almost 2 years + # 2 yrs <-> max time or date # => (same rules as 1 yr) # # With <tt>include_seconds</tt> = true and the difference < 1 minute 29 seconds: # 0-4 secs # => less than 5 seconds @@ -43,17 +45,18 @@ module ActionView # distance_of_time_in_words(from_time, 50.minutes.from_now) # => about 1 hour # distance_of_time_in_words(from_time, from_time + 15.seconds) # => less than a minute # distance_of_time_in_words(from_time, from_time + 15.seconds, true) # => less than 20 seconds - # distance_of_time_in_words(from_time, 3.years.from_now) # => over 3 years + # distance_of_time_in_words(from_time, 3.years.from_now) # => about 3 years # distance_of_time_in_words(from_time, from_time + 60.hours) # => about 3 days # distance_of_time_in_words(from_time, from_time + 45.seconds, true) # => less than a minute # distance_of_time_in_words(from_time, from_time - 45.seconds, true) # => less than a minute # distance_of_time_in_words(from_time, 76.seconds.from_now) # => 1 minute # distance_of_time_in_words(from_time, from_time + 1.year + 3.days) # => about 1 year - # distance_of_time_in_words(from_time, from_time + 4.years + 9.days + 30.minutes + 5.seconds) # => over 4 years + # distance_of_time_in_words(from_time, from_time + 3.years + 6.months) # => over 3 years + # distance_of_time_in_words(from_time, from_time + 4.years + 9.days + 30.minutes + 5.seconds) # => about 4 years # # to_time = Time.now + 6.years + 19.days - # distance_of_time_in_words(from_time, to_time, true) # => over 6 years - # distance_of_time_in_words(to_time, from_time, true) # => over 6 years + # distance_of_time_in_words(from_time, to_time, true) # => about 6 years + # distance_of_time_in_words(to_time, from_time, true) # => about 6 years # distance_of_time_in_words(Time.now, Time.now) # => less than a minute # def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false, options = {}) @@ -81,12 +84,21 @@ module ActionView when 2..44 then locale.t :x_minutes, :count => distance_in_minutes when 45..89 then locale.t :about_x_hours, :count => 1 when 90..1439 then locale.t :about_x_hours, :count => (distance_in_minutes.to_f / 60.0).round - when 1440..2879 then locale.t :x_days, :count => 1 - when 2880..43199 then locale.t :x_days, :count => (distance_in_minutes / 1440).round + when 1440..2529 then locale.t :x_days, :count => 1 + when 2530..43199 then locale.t :x_days, :count => (distance_in_minutes.to_f / 1440.0).round when 43200..86399 then locale.t :about_x_months, :count => 1 - when 86400..525599 then locale.t :x_months, :count => (distance_in_minutes / 43200).round - when 525600..1051199 then locale.t :about_x_years, :count => 1 - else locale.t :over_x_years, :count => (distance_in_minutes / 525600).round + when 86400..525599 then locale.t :x_months, :count => (distance_in_minutes.to_f / 43200.0).round + else + distance_in_years = distance_in_minutes / 525600 + minute_offset_for_leap_year = (distance_in_years / 4) * 1440 + remainder = ((distance_in_minutes - minute_offset_for_leap_year) % 525600) + if remainder < 131400 + locale.t(:about_x_years, :count => distance_in_years) + elsif remainder < 394200 + locale.t(:over_x_years, :count => distance_in_years) + else + locale.t(:almost_x_years, :count => distance_in_years + 1) + end end end end diff --git a/actionpack/lib/action_view/locale/en.yml b/actionpack/lib/action_view/locale/en.yml index c82cd07ec2..84d94fd700 100644 --- a/actionpack/lib/action_view/locale/en.yml +++ b/actionpack/lib/action_view/locale/en.yml @@ -91,6 +91,9 @@ over_x_years: one: "over 1 year" other: "over {{count}} years" + almost_x_years: + one: "almost 1 year" + other: "almost {{count}} years" prompts: year: "Year" month: "Month" diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb index b0b75918b7..0cab035ede 100644 --- a/actionpack/lib/action_view/render/rendering.rb +++ b/actionpack/lib/action_view/render/rendering.rb @@ -89,6 +89,7 @@ module ActionView def _render_text(text, layout, options) text = layout.render(self, options[:locals]) { text } if layout + text end # This is the API to render a ViewContext's template from a controller. @@ -105,7 +106,7 @@ module ActionView def _render_template(template, layout = nil, options = {}, partial = nil) logger && logger.info do - msg = "Rendering #{template.identifier}" + msg = "Rendering #{template.inspect}" msg << " (#{options[:status]})" if options[:status] msg end @@ -123,7 +124,7 @@ module ActionView if layout @_layout = layout.identifier - logger.info("Rendering template within #{layout.identifier}") if logger + logger.info("Rendering template within #{layout.inspect}") if logger content = layout.render(self, locals) {|*name| _layout_for(*name) } end content diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb index 6e5093c5bd..aa21606f76 100644 --- a/actionpack/lib/action_view/template/error.rb +++ b/actionpack/lib/action_view/template/error.rb @@ -32,7 +32,7 @@ module ActionView def sub_template_message if @sub_templates "Trace of template inclusion: " + - @sub_templates.collect { |template| template.identifier }.join(", ") + @sub_templates.collect { |template| template.inspect }.join(", ") else "" end diff --git a/actionpack/lib/action_view/template/handlers/builder.rb b/actionpack/lib/action_view/template/handlers/builder.rb index ba0d17b5af..5f381f7bf0 100644 --- a/actionpack/lib/action_view/template/handlers/builder.rb +++ b/actionpack/lib/action_view/template/handlers/builder.rb @@ -6,7 +6,7 @@ module ActionView self.default_format = Mime::XML def compile(template) - require 'active_support/vendor/builder' + require 'builder' "xml = ::Builder::XmlMarkup.new(:indent => 2);" + "self.output_buffer = xml.target!;" + template.source + diff --git a/actionpack/lib/action_view/template/template.rb b/actionpack/lib/action_view/template/template.rb index 80c1bab7d5..0f64c23649 100644 --- a/actionpack/lib/action_view/template/template.rb +++ b/actionpack/lib/action_view/template/template.rb @@ -8,7 +8,7 @@ module ActionView class Template extend TemplateHandlers attr_reader :source, :identifier, :handler, :mime_type, :formats, :details - + def initialize(source, identifier, handler, details) @source = source @identifier = identifier @@ -25,7 +25,7 @@ module ActionView @formats << :html if format == :js @details[:formats] = Array.wrap(format.to_sym) end - + def render(view, locals, &block) ActiveSupport::Orchestra.instrument(:render_template, :identifier => identifier) do method_name = compile(locals, view) @@ -39,7 +39,7 @@ module ActionView raise TemplateError.new(self, view.assigns, e) end end - + # TODO: Figure out how to abstract this def variable_name @variable_name ||= identifier[%r'_?(\w+)(\.\w+)*$', 1].to_sym @@ -49,76 +49,83 @@ module ActionView def counter_name @counter_name ||= "#{variable_name}_counter".to_sym end - + # TODO: kill hax def partial? @details[:partial] end - private + def inspect + if defined?(Rails.root) + identifier.sub("#{Rails.root}/", '') + else + identifier + end + end - def compile(locals, view) - method_name = build_method_name(locals) - - return method_name if view.respond_to?(method_name) - - locals_code = locals.keys.map! { |key| "#{key} = local_assigns[:#{key}];" }.join + private + def compile(locals, view) + method_name = build_method_name(locals) - code = @handler.call(self) - if code.sub!(/\A(#.*coding.*)\n/, '') - encoding_comment = $1 - elsif defined?(Encoding) && Encoding.respond_to?(:default_external) - encoding_comment = "#coding:#{Encoding.default_external}" - end + return method_name if view.respond_to?(method_name) - source = <<-end_src - def #{method_name}(local_assigns) - old_output_buffer = output_buffer;#{locals_code};#{code} - ensure - self.output_buffer = old_output_buffer - end - end_src + locals_code = locals.keys.map! { |key| "#{key} = local_assigns[:#{key}];" }.join - if encoding_comment - source = "#{encoding_comment}\n#{source}" - line = -1 - else - line = 0 - end + code = @handler.call(self) + if code.sub!(/\A(#.*coding.*)\n/, '') + encoding_comment = $1 + elsif defined?(Encoding) && Encoding.respond_to?(:default_external) + encoding_comment = "#coding:#{Encoding.default_external}" + end - begin - ActionView::CompiledTemplates.module_eval(source, identifier, line) - method_name - rescue Exception => e # errors from template code - if logger = (view && view.logger) - logger.debug "ERROR: compiling #{method_name} RAISED #{e}" - logger.debug "Function body: #{source}" - logger.debug "Backtrace: #{e.backtrace.join("\n")}" + source = <<-end_src + def #{method_name}(local_assigns) + old_output_buffer = output_buffer;#{locals_code};#{code} + ensure + self.output_buffer = old_output_buffer + end + end_src + + if encoding_comment + source = "#{encoding_comment}\n#{source}" + line = -1 + else + line = 0 end - raise ActionView::TemplateError.new(self, {}, e) + begin + ActionView::CompiledTemplates.module_eval(source, identifier, line) + method_name + rescue Exception => e # errors from template code + if logger = (view && view.logger) + logger.debug "ERROR: compiling #{method_name} RAISED #{e}" + logger.debug "Function body: #{source}" + logger.debug "Backtrace: #{e.backtrace.join("\n")}" + end + + raise ActionView::TemplateError.new(self, {}, e) + end end - end - class LocalsKey - @hash_keys = Hash.new {|h,k| h[k] = Hash.new {|h,k| h[k] = {} } } + class LocalsKey + @hash_keys = Hash.new {|h,k| h[k] = Hash.new {|h,k| h[k] = {} } } - def self.get(*locals) - @hash_keys[*locals] ||= new(klass, format, locale) - end + def self.get(*locals) + @hash_keys[*locals] ||= new(klass, format, locale) + end - attr_accessor :hash - def initialize(klass, format, locale) - @hash = locals.hash - end + attr_accessor :hash + def initialize(klass, format, locale) + @hash = locals.hash + end - alias_method :eql?, :equal? - end + alias_method :eql?, :equal? + end - def build_method_name(locals) - # TODO: is locals.keys.hash reliably the same? - @method_names[locals.keys.hash] ||= - "_render_template_#{@identifier.hash}_#{__id__}_#{locals.keys.hash}".gsub('-', "_") - end + def build_method_name(locals) + # TODO: is locals.keys.hash reliably the same? + @method_names[locals.keys.hash] ||= + "_render_template_#{@identifier.hash}_#{__id__}_#{locals.keys.hash}".gsub('-', "_") + end end end diff --git a/actionpack/lib/action_view/template/text.rb b/actionpack/lib/action_view/template/text.rb index 9f12e5e0a8..f7d0df5ba0 100644 --- a/actionpack/lib/action_view/template/text.rb +++ b/actionpack/lib/action_view/template/text.rb @@ -1,6 +1,5 @@ module ActionView #:nodoc: class TextTemplate < String #:nodoc: - def initialize(string, content_type = Mime[:html]) super(string.to_s) @content_type = Mime[content_type] || content_type @@ -10,14 +9,28 @@ module ActionView #:nodoc: {:formats => [@content_type.to_sym]} end - def identifier() self end - - def render(*) self end - - def mime_type() @content_type end + def identifier + self + end + + def inspect + 'inline template' + end + + def render(*args) + self + end - def formats() [mime_type] end + def mime_type + @content_type + end - def partial?() false end + def formats + [mime_type] + end + + def partial? + false + end end end diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index c2ccd1d3a5..441f462bc9 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -1,4 +1,5 @@ require 'active_support/test_case' +require 'action_controller/testing/test_case' module ActionView class Base @@ -23,12 +24,52 @@ module ActionView end class TestCase < ActiveSupport::TestCase + class TestController < ActionController::Base + attr_accessor :request, :response, :params + + def self.controller_path + '' + end + + def initialize + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + + @params = {} + end + end + include ActionDispatch::Assertions include ActionController::TestProcess include ActionView::Context + include ActionController::PolymorphicRoutes + include ActionController::RecordIdentifier + + include ActionView::Helpers + include ActionController::Helpers + class_inheritable_accessor :helper_class - @@helper_class = nil + attr_accessor :controller, :output_buffer, :rendered + + setup :setup_with_controller + def setup_with_controller + @controller = TestController.new + @output_buffer = '' + @rendered = '' + + self.class.send(:include_helper_modules!) + make_test_case_available_to_view! + end + + def render(options = {}, local_assigns = {}, &block) + @rendered << output = _view.render(options, local_assigns, &block) + output + end + + def protect_against_forgery? + false + end class << self def tests(helper_class) @@ -48,41 +89,75 @@ module ActionView rescue NameError nil end - end - include ActionView::Helpers - include ActionController::PolymorphicRoutes - include ActionController::RecordIdentifier - - setup :setup_with_helper_class - - def setup_with_helper_class - if helper_class && !self.class.ancestors.include?(helper_class) - self.class.send(:include, helper_class) + def helper_method(*methods) + # Almost a duplicate from ActionController::Helpers + methods.flatten.each do |method| + _helpers.module_eval <<-end_eval + def #{method}(*args, &block) # def current_user(*args, &block) + _test_case.send(%(#{method}), *args, &block) # test_case.send(%(current_user), *args, &block) + end # end + end_eval + end end - self.output_buffer = '' + private + def include_helper_modules! + helper(helper_class) if helper_class + include _helpers + end end - class TestController < ActionController::Base - attr_accessor :request, :response, :params + private + def make_test_case_available_to_view! + test_case_instance = self + _helpers.module_eval do + define_method(:_test_case) { test_case_instance } + private :_test_case + end + end - def initialize - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new + def _view + view = ActionView::Base.new(ActionController::Base.view_paths, _assigns, @controller) + view.class.send :include, _helpers + view + end - @params = {} + # Support the selector assertions + # + # Need to experiment if this priority is the best one: rendered => output_buffer + def response_from_page_or_rjs + HTML::Document.new(rendered.blank? ? output_buffer : rendered).root + end + + EXCLUDE_IVARS = %w{ + @output_buffer + @fixture_cache + @method_name + @_result + @loaded_fixtures + @test_passed + @view + } + + def _instance_variables + instance_variables - EXCLUDE_IVARS end - end - protected - attr_accessor :output_buffer + def _assigns + _instance_variables.inject({}) do |hash, var| + name = var[1..-1].to_sym + hash[name] = instance_variable_get(var) + hash + end + end - private def method_missing(selector, *args) - controller = TestController.new - return controller.__send__(selector, *args) if ActionController::Routing::Routes.named_routes.helpers.include?(selector) - super + if ActionController::Routing::Routes.named_routes.helpers.include?(selector) + @controller.__send__(selector, *args) + else + super + end end end end |