##// END OF EJS Templates
add patch for regression of Hash#reject in Ruby 2.1.1 (#16194)...
Toshi MARUYAMA -
r12840:82fa2cf79a29
parent child
Show More
@@ -1,236 +1,260
1 require 'active_record'
1 require 'active_record'
2
2
3 module ActiveRecord
3 module ActiveRecord
4 class Base
4 class Base
5 include Redmine::I18n
5 include Redmine::I18n
6 # Translate attribute names for validation errors display
6 # Translate attribute names for validation errors display
7 def self.human_attribute_name(attr, *args)
7 def self.human_attribute_name(attr, *args)
8 attr = attr.to_s.sub(/_id$/, '')
8 attr = attr.to_s.sub(/_id$/, '')
9
9
10 l("field_#{name.underscore.gsub('/', '_')}_#{attr}", :default => ["field_#{attr}".to_sym, attr])
10 l("field_#{name.underscore.gsub('/', '_')}_#{attr}", :default => ["field_#{attr}".to_sym, attr])
11 end
11 end
12 end
12 end
13
13
14 # Undefines private Kernel#open method to allow using `open` scopes in models.
14 # Undefines private Kernel#open method to allow using `open` scopes in models.
15 # See Defect #11545 (http://www.redmine.org/issues/11545) for details.
15 # See Defect #11545 (http://www.redmine.org/issues/11545) for details.
16 class Base
16 class Base
17 class << self
17 class << self
18 undef open
18 undef open
19 end
19 end
20 end
20 end
21 class Relation ; undef open ; end
21 class Relation ; undef open ; end
22 end
22 end
23
23
24 module ActionView
24 module ActionView
25 module Helpers
25 module Helpers
26 module DateHelper
26 module DateHelper
27 # distance_of_time_in_words breaks when difference is greater than 30 years
27 # distance_of_time_in_words breaks when difference is greater than 30 years
28 def distance_of_date_in_words(from_date, to_date = 0, options = {})
28 def distance_of_date_in_words(from_date, to_date = 0, options = {})
29 from_date = from_date.to_date if from_date.respond_to?(:to_date)
29 from_date = from_date.to_date if from_date.respond_to?(:to_date)
30 to_date = to_date.to_date if to_date.respond_to?(:to_date)
30 to_date = to_date.to_date if to_date.respond_to?(:to_date)
31 distance_in_days = (to_date - from_date).abs
31 distance_in_days = (to_date - from_date).abs
32
32
33 I18n.with_options :locale => options[:locale], :scope => :'datetime.distance_in_words' do |locale|
33 I18n.with_options :locale => options[:locale], :scope => :'datetime.distance_in_words' do |locale|
34 case distance_in_days
34 case distance_in_days
35 when 0..60 then locale.t :x_days, :count => distance_in_days.round
35 when 0..60 then locale.t :x_days, :count => distance_in_days.round
36 when 61..720 then locale.t :about_x_months, :count => (distance_in_days / 30).round
36 when 61..720 then locale.t :about_x_months, :count => (distance_in_days / 30).round
37 else locale.t :over_x_years, :count => (distance_in_days / 365).floor
37 else locale.t :over_x_years, :count => (distance_in_days / 365).floor
38 end
38 end
39 end
39 end
40 end
40 end
41 end
41 end
42 end
42 end
43
43
44 class Resolver
44 class Resolver
45 def find_all(name, prefix=nil, partial=false, details={}, key=nil, locals=[])
45 def find_all(name, prefix=nil, partial=false, details={}, key=nil, locals=[])
46 cached(key, [name, prefix, partial], details, locals) do
46 cached(key, [name, prefix, partial], details, locals) do
47 if details[:formats] & [:xml, :json]
47 if details[:formats] & [:xml, :json]
48 details = details.dup
48 details = details.dup
49 details[:formats] = details[:formats].dup + [:api]
49 details[:formats] = details[:formats].dup + [:api]
50 end
50 end
51 find_templates(name, prefix, partial, details)
51 find_templates(name, prefix, partial, details)
52 end
52 end
53 end
53 end
54 end
54 end
55 end
55 end
56
56
57 # Do not HTML escape text templates
57 # Do not HTML escape text templates
58 module ActionView
58 module ActionView
59 class Template
59 class Template
60 module Handlers
60 module Handlers
61 class ERB
61 class ERB
62 def call(template)
62 def call(template)
63 if template.source.encoding_aware?
63 if template.source.encoding_aware?
64 # First, convert to BINARY, so in case the encoding is
64 # First, convert to BINARY, so in case the encoding is
65 # wrong, we can still find an encoding tag
65 # wrong, we can still find an encoding tag
66 # (<%# encoding %>) inside the String using a regular
66 # (<%# encoding %>) inside the String using a regular
67 # expression
67 # expression
68 template_source = template.source.dup.force_encoding("BINARY")
68 template_source = template.source.dup.force_encoding("BINARY")
69
69
70 erb = template_source.gsub(ENCODING_TAG, '')
70 erb = template_source.gsub(ENCODING_TAG, '')
71 encoding = $2
71 encoding = $2
72
72
73 erb.force_encoding valid_encoding(template.source.dup, encoding)
73 erb.force_encoding valid_encoding(template.source.dup, encoding)
74
74
75 # Always make sure we return a String in the default_internal
75 # Always make sure we return a String in the default_internal
76 erb.encode!
76 erb.encode!
77 else
77 else
78 erb = template.source.dup
78 erb = template.source.dup
79 end
79 end
80
80
81 self.class.erb_implementation.new(
81 self.class.erb_implementation.new(
82 erb,
82 erb,
83 :trim => (self.class.erb_trim_mode == "-"),
83 :trim => (self.class.erb_trim_mode == "-"),
84 :escape => template.identifier =~ /\.text/ # only escape HTML templates
84 :escape => template.identifier =~ /\.text/ # only escape HTML templates
85 ).src
85 ).src
86 end
86 end
87 end
87 end
88 end
88 end
89 end
89 end
90 end
90 end
91
91
92 ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| html_tag || ''.html_safe }
92 ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| html_tag || ''.html_safe }
93
93
94 # HTML5: <option value=""></option> is invalid, use <option value="">&nbsp;</option> instead
94 # HTML5: <option value=""></option> is invalid, use <option value="">&nbsp;</option> instead
95 module ActionView
95 module ActionView
96 module Helpers
96 module Helpers
97 class InstanceTag
97 class InstanceTag
98 private
98 private
99 def add_options_with_non_empty_blank_option(option_tags, options, value = nil)
99 def add_options_with_non_empty_blank_option(option_tags, options, value = nil)
100 if options[:include_blank] == true
100 if options[:include_blank] == true
101 options = options.dup
101 options = options.dup
102 options[:include_blank] = '&nbsp;'.html_safe
102 options[:include_blank] = '&nbsp;'.html_safe
103 end
103 end
104 add_options_without_non_empty_blank_option(option_tags, options, value)
104 add_options_without_non_empty_blank_option(option_tags, options, value)
105 end
105 end
106 alias_method_chain :add_options, :non_empty_blank_option
106 alias_method_chain :add_options, :non_empty_blank_option
107 end
107 end
108
108
109 module FormTagHelper
109 module FormTagHelper
110 def select_tag_with_non_empty_blank_option(name, option_tags = nil, options = {})
110 def select_tag_with_non_empty_blank_option(name, option_tags = nil, options = {})
111 if options.delete(:include_blank)
111 if options.delete(:include_blank)
112 options[:prompt] = '&nbsp;'.html_safe
112 options[:prompt] = '&nbsp;'.html_safe
113 end
113 end
114 select_tag_without_non_empty_blank_option(name, option_tags, options)
114 select_tag_without_non_empty_blank_option(name, option_tags, options)
115 end
115 end
116 alias_method_chain :select_tag, :non_empty_blank_option
116 alias_method_chain :select_tag, :non_empty_blank_option
117 end
117 end
118
118
119 module FormOptionsHelper
119 module FormOptionsHelper
120 def options_for_select_with_non_empty_blank_option(container, selected = nil)
120 def options_for_select_with_non_empty_blank_option(container, selected = nil)
121 if container.is_a?(Array)
121 if container.is_a?(Array)
122 container = container.map {|element| element.blank? ? ["&nbsp;".html_safe, ""] : element}
122 container = container.map {|element| element.blank? ? ["&nbsp;".html_safe, ""] : element}
123 end
123 end
124 options_for_select_without_non_empty_blank_option(container, selected)
124 options_for_select_without_non_empty_blank_option(container, selected)
125 end
125 end
126 alias_method_chain :options_for_select, :non_empty_blank_option
126 alias_method_chain :options_for_select, :non_empty_blank_option
127 end
127 end
128 end
128 end
129 end
129 end
130
130
131 require 'mail'
131 require 'mail'
132
132
133 module DeliveryMethods
133 module DeliveryMethods
134 class AsyncSMTP < ::Mail::SMTP
134 class AsyncSMTP < ::Mail::SMTP
135 def deliver!(*args)
135 def deliver!(*args)
136 Thread.start do
136 Thread.start do
137 super *args
137 super *args
138 end
138 end
139 end
139 end
140 end
140 end
141
141
142 class AsyncSendmail < ::Mail::Sendmail
142 class AsyncSendmail < ::Mail::Sendmail
143 def deliver!(*args)
143 def deliver!(*args)
144 Thread.start do
144 Thread.start do
145 super *args
145 super *args
146 end
146 end
147 end
147 end
148 end
148 end
149
149
150 class TmpFile
150 class TmpFile
151 def initialize(*args); end
151 def initialize(*args); end
152
152
153 def deliver!(mail)
153 def deliver!(mail)
154 dest_dir = File.join(Rails.root, 'tmp', 'emails')
154 dest_dir = File.join(Rails.root, 'tmp', 'emails')
155 Dir.mkdir(dest_dir) unless File.directory?(dest_dir)
155 Dir.mkdir(dest_dir) unless File.directory?(dest_dir)
156 File.open(File.join(dest_dir, mail.message_id.gsub(/[<>]/, '') + '.eml'), 'wb') {|f| f.write(mail.encoded) }
156 File.open(File.join(dest_dir, mail.message_id.gsub(/[<>]/, '') + '.eml'), 'wb') {|f| f.write(mail.encoded) }
157 end
157 end
158 end
158 end
159 end
159 end
160
160
161 ActionMailer::Base.add_delivery_method :async_smtp, DeliveryMethods::AsyncSMTP
161 ActionMailer::Base.add_delivery_method :async_smtp, DeliveryMethods::AsyncSMTP
162 ActionMailer::Base.add_delivery_method :async_sendmail, DeliveryMethods::AsyncSendmail
162 ActionMailer::Base.add_delivery_method :async_sendmail, DeliveryMethods::AsyncSendmail
163 ActionMailer::Base.add_delivery_method :tmp_file, DeliveryMethods::TmpFile
163 ActionMailer::Base.add_delivery_method :tmp_file, DeliveryMethods::TmpFile
164
164
165 # Changes how sent emails are logged
165 # Changes how sent emails are logged
166 # Rails doesn't log cc and bcc which is misleading when using bcc only (#12090)
166 # Rails doesn't log cc and bcc which is misleading when using bcc only (#12090)
167 module ActionMailer
167 module ActionMailer
168 class LogSubscriber < ActiveSupport::LogSubscriber
168 class LogSubscriber < ActiveSupport::LogSubscriber
169 def deliver(event)
169 def deliver(event)
170 recipients = [:to, :cc, :bcc].inject("") do |s, header|
170 recipients = [:to, :cc, :bcc].inject("") do |s, header|
171 r = Array.wrap(event.payload[header])
171 r = Array.wrap(event.payload[header])
172 if r.any?
172 if r.any?
173 s << "\n #{header}: #{r.join(', ')}"
173 s << "\n #{header}: #{r.join(', ')}"
174 end
174 end
175 s
175 s
176 end
176 end
177 info("\nSent email \"#{event.payload[:subject]}\" (%1.fms)#{recipients}" % event.duration)
177 info("\nSent email \"#{event.payload[:subject]}\" (%1.fms)#{recipients}" % event.duration)
178 debug(event.payload[:mail])
178 debug(event.payload[:mail])
179 end
179 end
180 end
180 end
181 end
181 end
182
182
183 module ActionController
183 module ActionController
184 module MimeResponds
184 module MimeResponds
185 class Collector
185 class Collector
186 def api(&block)
186 def api(&block)
187 any(:xml, :json, &block)
187 any(:xml, :json, &block)
188 end
188 end
189 end
189 end
190 end
190 end
191 end
191 end
192
192
193 module ActionController
193 module ActionController
194 class Base
194 class Base
195 # Displays an explicit message instead of a NoMethodError exception
195 # Displays an explicit message instead of a NoMethodError exception
196 # when trying to start Redmine with an old session_store.rb
196 # when trying to start Redmine with an old session_store.rb
197 # TODO: remove it in a later version
197 # TODO: remove it in a later version
198 def self.session=(*args)
198 def self.session=(*args)
199 $stderr.puts "Please remove config/initializers/session_store.rb and run `rake generate_secret_token`.\n" +
199 $stderr.puts "Please remove config/initializers/session_store.rb and run `rake generate_secret_token`.\n" +
200 "Setting the session secret with ActionController.session= is no longer supported in Rails 3."
200 "Setting the session secret with ActionController.session= is no longer supported in Rails 3."
201 exit 1
201 exit 1
202 end
202 end
203 end
203 end
204 end
204 end
205
205
206 if Rails::VERSION::MAJOR < 4 && RUBY_VERSION >= "2.1"
207 module ActiveSupport
208 class HashWithIndifferentAccess
209 def select(*args, &block)
210 dup.tap { |hash| hash.select!(*args, &block) }
211 end
212
213 def reject(*args, &block)
214 dup.tap { |hash| hash.reject!(*args, &block) }
215 end
216 end
217
218 class OrderedHash
219 def select(*args, &block)
220 dup.tap { |hash| hash.select!(*args, &block) }
221 end
222
223 def reject(*args, &block)
224 dup.tap { |hash| hash.reject!(*args, &block) }
225 end
226 end
227 end
228 end
229
206 require 'awesome_nested_set/version'
230 require 'awesome_nested_set/version'
207
231
208 module CollectiveIdea
232 module CollectiveIdea
209 module Acts
233 module Acts
210 module NestedSet
234 module NestedSet
211 module Model
235 module Model
212 def leaf_with_new_record?
236 def leaf_with_new_record?
213 new_record? || leaf_without_new_record?
237 new_record? || leaf_without_new_record?
214 end
238 end
215 alias_method_chain :leaf?, :new_record
239 alias_method_chain :leaf?, :new_record
216 # Reload is needed because children may have updated
240 # Reload is needed because children may have updated
217 # their parent (self) during deletion.
241 # their parent (self) during deletion.
218 if ::AwesomeNestedSet::VERSION > "2.1.6"
242 if ::AwesomeNestedSet::VERSION > "2.1.6"
219 module Prunable
243 module Prunable
220 def destroy_descendants_with_reload
244 def destroy_descendants_with_reload
221 destroy_descendants_without_reload
245 destroy_descendants_without_reload
222 reload
246 reload
223 end
247 end
224 alias_method_chain :destroy_descendants, :reload
248 alias_method_chain :destroy_descendants, :reload
225 end
249 end
226 else
250 else
227 def destroy_descendants_with_reload
251 def destroy_descendants_with_reload
228 destroy_descendants_without_reload
252 destroy_descendants_without_reload
229 reload
253 reload
230 end
254 end
231 alias_method_chain :destroy_descendants, :reload
255 alias_method_chain :destroy_descendants, :reload
232 end
256 end
233 end
257 end
234 end
258 end
235 end
259 end
236 end
260 end
@@ -1,38 +1,99
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class PatchesTest < ActiveSupport::TestCase
20 class PatchesTest < ActiveSupport::TestCase
21 include Redmine::I18n
21 include Redmine::I18n
22
22
23 def setup
23 def setup
24 Setting.default_language = 'en'
24 Setting.default_language = 'en'
25 @symbols = { :a => 1, :b => 2 }
26 @keys = %w( blue green red pink orange )
27 @values = %w( 000099 009900 aa0000 cc0066 cc6633 )
28 @hash = Hash.new
29 @ordered_hash = ActiveSupport::OrderedHash.new
30
31 @keys.each_with_index do |key, index|
32 @hash[key] = @values[index]
33 @ordered_hash[key] = @values[index]
34 end
25 end
35 end
26
36
27 test "ActiveRecord::Base.human_attribute_name should transform name to field_name" do
37 test "ActiveRecord::Base.human_attribute_name should transform name to field_name" do
28 assert_equal l('field_last_login_on'), ActiveRecord::Base.human_attribute_name('last_login_on')
38 assert_equal l('field_last_login_on'), ActiveRecord::Base.human_attribute_name('last_login_on')
29 end
39 end
30
40
31 test "ActiveRecord::Base.human_attribute_name should cut extra _id suffix for better validation" do
41 test "ActiveRecord::Base.human_attribute_name should cut extra _id suffix for better validation" do
32 assert_equal l('field_last_login_on'), ActiveRecord::Base.human_attribute_name('last_login_on_id')
42 assert_equal l('field_last_login_on'), ActiveRecord::Base.human_attribute_name('last_login_on_id')
33 end
43 end
34
44
35 test "ActiveRecord::Base.human_attribute_name should default to humanized value if no translation has been found (useful for custom fields)" do
45 test "ActiveRecord::Base.human_attribute_name should default to humanized value if no translation has been found (useful for custom fields)" do
36 assert_equal 'Patch name', ActiveRecord::Base.human_attribute_name('Patch name')
46 assert_equal 'Patch name', ActiveRecord::Base.human_attribute_name('Patch name')
37 end
47 end
48
49 # https://github.com/rails/rails/pull/14198/files
50 if RUBY_VERSION >= "1.9"
51 def test_indifferent_select
52 hash = ActiveSupport::HashWithIndifferentAccess.new(@symbols).select { |_ ,v| v == 1 }
53 assert_equal({ 'a' => 1 }, hash)
54 assert_instance_of (RUBY_VERSION < "2.1" ?
55 Hash : ActiveSupport::HashWithIndifferentAccess),
56 hash
57 end
58
59 def test_indifferent_select_bang
60 indifferent_strings = ActiveSupport::HashWithIndifferentAccess.new(@symbols)
61 indifferent_strings.select! { |_, v| v == 1 }
62 assert_equal({ 'a' => 1 }, indifferent_strings)
63 assert_instance_of ActiveSupport::HashWithIndifferentAccess, indifferent_strings
64 end
65 end
66
67 def test_indifferent_reject
68 hash = ActiveSupport::HashWithIndifferentAccess.new(@symbols).reject { |_, v| v != 1 }
69 assert_equal({ 'a' => 1 }, hash)
70 assert_instance_of ActiveSupport::HashWithIndifferentAccess, hash
71 end
72
73 def test_indifferent_reject_bang
74 indifferent_strings = ActiveSupport::HashWithIndifferentAccess.new(@symbols)
75 indifferent_strings.reject! { |_, v| v != 1 }
76 assert_equal({ 'a' => 1 }, indifferent_strings)
77 assert_instance_of ActiveSupport::HashWithIndifferentAccess, indifferent_strings
78 end
79
80 if RUBY_VERSION >= "1.9"
81 def test_select
82 assert_equal @keys, @ordered_hash.select { true }.map(&:first)
83 new_ordered_hash = @ordered_hash.select { true }
84 assert_equal @keys, new_ordered_hash.map(&:first)
85 assert_instance_of (RUBY_VERSION < "2.1" ?
86 Hash : ActiveSupport::OrderedHash),
87 new_ordered_hash
88 end
89 end
90
91 def test_reject
92 copy = @ordered_hash.dup
93 new_ordered_hash = @ordered_hash.reject { |k, _| k == 'pink' }
94 assert_equal copy, @ordered_hash
95 assert !new_ordered_hash.keys.include?('pink')
96 assert @ordered_hash.keys.include?('pink')
97 assert_instance_of ActiveSupport::OrderedHash, new_ordered_hash
98 end
38 end
99 end
General Comments 0
You need to be logged in to leave comments. Login now