hashie 2.0.5 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rubocop.yml +36 -0
- data/.travis.yml +13 -6
- data/CHANGELOG.md +40 -21
- data/CONTRIBUTING.md +110 -19
- data/Gemfile +9 -0
- data/LICENSE +1 -1
- data/README.md +347 -0
- data/Rakefile +4 -2
- data/hashie.gemspec +4 -7
- data/lib/hashie.rb +3 -0
- data/lib/hashie/clash.rb +19 -19
- data/lib/hashie/dash.rb +47 -39
- data/lib/hashie/extensions/coercion.rb +10 -6
- data/lib/hashie/extensions/deep_fetch.rb +29 -0
- data/lib/hashie/extensions/deep_merge.rb +15 -6
- data/lib/hashie/extensions/ignore_undeclared.rb +41 -0
- data/lib/hashie/extensions/indifferent_access.rb +37 -10
- data/lib/hashie/extensions/key_conversion.rb +3 -3
- data/lib/hashie/extensions/method_access.rb +9 -9
- data/lib/hashie/hash.rb +7 -7
- data/lib/hashie/hash_extensions.rb +5 -7
- data/lib/hashie/mash.rb +38 -31
- data/lib/hashie/rash.rb +119 -0
- data/lib/hashie/trash.rb +31 -22
- data/lib/hashie/version.rb +1 -1
- data/spec/hashie/clash_spec.rb +43 -45
- data/spec/hashie/dash_spec.rb +115 -53
- data/spec/hashie/extensions/coercion_spec.rb +42 -37
- data/spec/hashie/extensions/deep_fetch_spec.rb +70 -0
- data/spec/hashie/extensions/deep_merge_spec.rb +11 -9
- data/spec/hashie/extensions/ignore_undeclared_spec.rb +23 -0
- data/spec/hashie/extensions/indifferent_access_spec.rb +117 -64
- data/spec/hashie/extensions/key_conversion_spec.rb +28 -27
- data/spec/hashie/extensions/merge_initializer_spec.rb +13 -10
- data/spec/hashie/extensions/method_access_spec.rb +49 -40
- data/spec/hashie/hash_spec.rb +25 -13
- data/spec/hashie/mash_spec.rb +243 -187
- data/spec/hashie/rash_spec.rb +44 -0
- data/spec/hashie/trash_spec.rb +81 -43
- data/spec/hashie/version_spec.rb +7 -0
- data/spec/spec_helper.rb +0 -4
- metadata +27 -78
- data/.document +0 -5
- data/README.markdown +0 -236
- data/lib/hashie/extensions/structure.rb +0 -47
@@ -10,7 +10,7 @@ module Hashie
|
|
10
10
|
def stringify_keys!
|
11
11
|
keys.each do |k|
|
12
12
|
stringify_keys_recursively!(self[k])
|
13
|
-
self[k.to_s] =
|
13
|
+
self[k.to_s] = delete(k)
|
14
14
|
end
|
15
15
|
self
|
16
16
|
end
|
@@ -51,7 +51,7 @@ module Hashie
|
|
51
51
|
def symbolize_keys!
|
52
52
|
keys.each do |k|
|
53
53
|
symbolize_keys_recursively!(self[k])
|
54
|
-
self[k.to_sym] =
|
54
|
+
self[k.to_sym] = delete(k)
|
55
55
|
end
|
56
56
|
self
|
57
57
|
end
|
@@ -81,7 +81,7 @@ module Hashie
|
|
81
81
|
end
|
82
82
|
end
|
83
83
|
end
|
84
|
-
|
84
|
+
|
85
85
|
module KeyConversion
|
86
86
|
def self.included(base)
|
87
87
|
base.send :include, SymbolizeKeys
|
@@ -5,8 +5,8 @@ module Hashie
|
|
5
5
|
# to access your hash's keys. It will recognize keys
|
6
6
|
# either as strings or symbols.
|
7
7
|
#
|
8
|
-
# Note that while nil keys will be returned as nil,
|
9
|
-
# undefined keys will raise NoMethodErrors. Also note that
|
8
|
+
# Note that while nil keys will be returned as nil,
|
9
|
+
# undefined keys will raise NoMethodErrors. Also note that
|
10
10
|
# #respond_to? has been patched to appropriately recognize
|
11
11
|
# key methods.
|
12
12
|
#
|
@@ -18,9 +18,9 @@ module Hashie
|
|
18
18
|
# user = User.new
|
19
19
|
# user['first_name'] = 'Michael'
|
20
20
|
# user.first_name # => 'Michael'
|
21
|
-
#
|
21
|
+
#
|
22
22
|
# user[:last_name] = 'Bleigh'
|
23
|
-
# user.last_name # => 'Bleigh'
|
23
|
+
# user.last_name # => 'Bleigh'
|
24
24
|
#
|
25
25
|
# user[:birthday] = nil
|
26
26
|
# user.birthday # => nil
|
@@ -31,7 +31,7 @@ module Hashie
|
|
31
31
|
return true if key?(name.to_s) || key?(name.to_sym)
|
32
32
|
super
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
def method_missing(name, *args)
|
36
36
|
return self[name.to_s] if key?(name.to_s)
|
37
37
|
return self[name.to_sym] if key?(name.to_sym)
|
@@ -64,7 +64,7 @@ module Hashie
|
|
64
64
|
|
65
65
|
def method_missing(name, *args)
|
66
66
|
if args.size == 1 && name.to_s =~ /(.*)=$/
|
67
|
-
return self[convert_key(
|
67
|
+
return self[convert_key(Regexp.last_match[1])] = args.first
|
68
68
|
end
|
69
69
|
|
70
70
|
super
|
@@ -97,13 +97,13 @@ module Hashie
|
|
97
97
|
# h.hji? # => NoMethodError
|
98
98
|
module MethodQuery
|
99
99
|
def respond_to?(name, include_private = false)
|
100
|
-
return true if name.to_s =~ /(.*)\?$/ && (key?(
|
100
|
+
return true if name.to_s =~ /(.*)\?$/ && (key?(Regexp.last_match[1]) || key?(Regexp.last_match[1].to_sym))
|
101
101
|
super
|
102
102
|
end
|
103
103
|
|
104
104
|
def method_missing(name, *args)
|
105
|
-
if args.empty? && name.to_s =~ /(.*)\?$/ && (key?(
|
106
|
-
return self[
|
105
|
+
if args.empty? && name.to_s =~ /(.*)\?$/ && (key?(Regexp.last_match[1]) || key?(Regexp.last_match[1].to_sym))
|
106
|
+
return self[Regexp.last_match[1]] || self[Regexp.last_match[1].to_sym]
|
107
107
|
end
|
108
108
|
|
109
109
|
super
|
data/lib/hashie/hash.rb
CHANGED
@@ -7,19 +7,19 @@ module Hashie
|
|
7
7
|
class Hash < ::Hash
|
8
8
|
include HashExtensions
|
9
9
|
|
10
|
-
# Converts a mash back to a hash (with stringified keys)
|
11
|
-
def to_hash(options={})
|
10
|
+
# Converts a mash back to a hash (with stringified or symbolized keys)
|
11
|
+
def to_hash(options = {})
|
12
12
|
out = {}
|
13
13
|
keys.each do |k|
|
14
|
+
assignment_key = k.to_s
|
15
|
+
assignment_key = assignment_key.to_sym if options[:symbolize_keys]
|
14
16
|
if self[k].is_a?(Array)
|
15
|
-
|
16
|
-
out[k] ||= []
|
17
|
+
out[assignment_key] ||= []
|
17
18
|
self[k].each do |array_object|
|
18
|
-
out[
|
19
|
+
out[assignment_key] << (Hash === array_object ? array_object.to_hash(options) : array_object)
|
19
20
|
end
|
20
21
|
else
|
21
|
-
|
22
|
-
out[k] = Hash === self[k] ? self[k].to_hash : self[k]
|
22
|
+
out[assignment_key] = Hash === self[k] ? self[k].to_hash(options) : self[k]
|
23
23
|
end
|
24
24
|
end
|
25
25
|
out
|
@@ -11,10 +11,8 @@ module Hashie
|
|
11
11
|
# Destructively convert all of the keys of a Hash
|
12
12
|
# to their string representations.
|
13
13
|
def hashie_stringify_keys!
|
14
|
-
|
15
|
-
unless String === k
|
16
|
-
self[k.to_s] = self.delete(k)
|
17
|
-
end
|
14
|
+
keys.each do |k|
|
15
|
+
self[k.to_s] = delete(k) unless String === k
|
18
16
|
end
|
19
17
|
self
|
20
18
|
end
|
@@ -22,7 +20,7 @@ module Hashie
|
|
22
20
|
# Convert all of the keys of a Hash
|
23
21
|
# to their string representations.
|
24
22
|
def hashie_stringify_keys
|
25
|
-
|
23
|
+
dup.stringify_keys!
|
26
24
|
end
|
27
25
|
|
28
26
|
# Convert this hash into a Mash
|
@@ -38,11 +36,11 @@ module Hashie
|
|
38
36
|
end
|
39
37
|
|
40
38
|
def hashie_inspect
|
41
|
-
ret = "#<#{self.class
|
39
|
+
ret = "#<#{self.class}"
|
42
40
|
stringify_keys.keys.sort.each do |key|
|
43
41
|
ret << " #{key}=#{self[key].inspect}"
|
44
42
|
end
|
45
|
-
ret <<
|
43
|
+
ret << '>'
|
46
44
|
ret
|
47
45
|
end
|
48
46
|
end
|
data/lib/hashie/mash.rb
CHANGED
@@ -55,6 +55,7 @@ module Hashie
|
|
55
55
|
# mash.author # => <Mash>
|
56
56
|
#
|
57
57
|
class Mash < Hash
|
58
|
+
ALLOWED_SUFFIXES = %w(? ! = _)
|
58
59
|
include Hashie::PrettyInspect
|
59
60
|
alias_method :to_s, :inspect
|
60
61
|
|
@@ -67,14 +68,14 @@ module Hashie
|
|
67
68
|
default ? super(default) : super(&blk)
|
68
69
|
end
|
69
70
|
|
70
|
-
class << self;
|
71
|
+
class << self; alias_method :[], :new; end
|
71
72
|
|
72
73
|
def id #:nodoc:
|
73
|
-
self[
|
74
|
+
self['id']
|
74
75
|
end
|
75
76
|
|
76
77
|
def type #:nodoc:
|
77
|
-
self[
|
78
|
+
self['type']
|
78
79
|
end
|
79
80
|
|
80
81
|
alias_method :regular_reader, :[]
|
@@ -91,8 +92,8 @@ module Hashie
|
|
91
92
|
# Sets an attribute in the Mash. Key will be converted to
|
92
93
|
# a string before it is set, and Hashes will be converted
|
93
94
|
# into Mashes for nesting purposes.
|
94
|
-
def custom_writer(key,value) #:nodoc:
|
95
|
-
regular_writer(convert_key(key), convert_value(value))
|
95
|
+
def custom_writer(key, value, convert = true) #:nodoc:
|
96
|
+
regular_writer(convert_key(key), convert ? convert_value(value) : value)
|
96
97
|
end
|
97
98
|
|
98
99
|
alias_method :[], :custom_reader
|
@@ -128,7 +129,7 @@ module Hashie
|
|
128
129
|
alias_method :regular_dup, :dup
|
129
130
|
# Duplicates the current mash as a new mash.
|
130
131
|
def dup
|
131
|
-
self.class.new(self,
|
132
|
+
self.class.new(self, default)
|
132
133
|
end
|
133
134
|
|
134
135
|
def key?(key)
|
@@ -148,14 +149,14 @@ module Hashie
|
|
148
149
|
# Recursively merges this mash with the passed
|
149
150
|
# in hash, merging each hash in the hierarchy.
|
150
151
|
def deep_update(other_hash, &blk)
|
151
|
-
other_hash.each_pair do |k,v|
|
152
|
+
other_hash.each_pair do |k, v|
|
152
153
|
key = convert_key(k)
|
153
|
-
if regular_reader(key).is_a?(Mash)
|
154
|
+
if regular_reader(key).is_a?(Mash) && v.is_a?(::Hash)
|
154
155
|
custom_reader(key).deep_update(v, &blk)
|
155
156
|
else
|
156
157
|
value = convert_value(v, true)
|
157
|
-
value = blk.call(key, self[k], value) if blk
|
158
|
-
custom_writer(key, value)
|
158
|
+
value = convert_value(blk.call(key, self[k], value), true) if blk
|
159
|
+
custom_writer(key, value, false)
|
159
160
|
end
|
160
161
|
end
|
161
162
|
self
|
@@ -172,7 +173,7 @@ module Hashie
|
|
172
173
|
# Merges (non-recursively) the hash from the argument,
|
173
174
|
# changing the receiving hash
|
174
175
|
def shallow_update(other_hash)
|
175
|
-
other_hash.each_pair do |k,v|
|
176
|
+
other_hash.each_pair do |k, v|
|
176
177
|
regular_writer(convert_key(k), convert_value(v, true))
|
177
178
|
end
|
178
179
|
self
|
@@ -186,25 +187,31 @@ module Hashie
|
|
186
187
|
|
187
188
|
# Will return true if the Mash has had a key
|
188
189
|
# set in addition to normal respond_to? functionality.
|
189
|
-
def respond_to?(method_name, include_private=false)
|
190
|
-
return true if key?(method_name) || method_name
|
190
|
+
def respond_to?(method_name, include_private = false)
|
191
|
+
return true if key?(method_name) || prefix_method?(method_name)
|
191
192
|
super
|
192
193
|
end
|
193
194
|
|
195
|
+
def prefix_method?(method_name)
|
196
|
+
method_name = method_name.to_s
|
197
|
+
method_name.end_with?(*ALLOWED_SUFFIXES) && key?(method_name.chop)
|
198
|
+
end
|
199
|
+
|
194
200
|
def method_missing(method_name, *args, &blk)
|
195
201
|
return self.[](method_name, &blk) if key?(method_name)
|
196
|
-
|
202
|
+
suffixes_regex = ALLOWED_SUFFIXES.join
|
203
|
+
match = method_name.to_s.match(/(.*?)([#{suffixes_regex}]?)$/)
|
197
204
|
case match[2]
|
198
|
-
when
|
205
|
+
when '='
|
199
206
|
self[match[1]] = args.first
|
200
|
-
when
|
207
|
+
when '?'
|
201
208
|
!!self[match[1]]
|
202
|
-
when
|
209
|
+
when '!'
|
203
210
|
initializing_reader(match[1])
|
204
|
-
when
|
211
|
+
when '_'
|
205
212
|
underbang_reader(match[1])
|
206
213
|
else
|
207
|
-
default(method_name
|
214
|
+
default(method_name)
|
208
215
|
end
|
209
216
|
end
|
210
217
|
|
@@ -214,19 +221,19 @@ module Hashie
|
|
214
221
|
key.to_s
|
215
222
|
end
|
216
223
|
|
217
|
-
def convert_value(val, duping=false) #:nodoc:
|
224
|
+
def convert_value(val, duping = false) #:nodoc:
|
218
225
|
case val
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
226
|
+
when self.class
|
227
|
+
val.dup
|
228
|
+
when Hash
|
229
|
+
duping ? val.dup : val
|
230
|
+
when ::Hash
|
231
|
+
val = val.dup if duping
|
232
|
+
self.class.new(val)
|
233
|
+
when Array
|
234
|
+
val.map { |e| convert_value(e) }
|
235
|
+
else
|
236
|
+
val
|
230
237
|
end
|
231
238
|
end
|
232
239
|
end
|
data/lib/hashie/rash.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
module Hashie
|
2
|
+
#
|
3
|
+
# Rash is a Hash whose keys can be Regexps, or Ranges, which will
|
4
|
+
# match many input keys.
|
5
|
+
#
|
6
|
+
# A good use case for this class is routing URLs in a web framework.
|
7
|
+
# The Rash's keys match URL patterns, and the values specify actions
|
8
|
+
# which can handle the URL. When the Rash's value is proc, the proc
|
9
|
+
# will be automatically called with the regexp's matched groups as
|
10
|
+
# block arguments.
|
11
|
+
#
|
12
|
+
# Usage example:
|
13
|
+
#
|
14
|
+
# greeting = Hashie::Rash.new( /^Mr./ => "Hello sir!", /^Mrs./ => "Evening, madame." )
|
15
|
+
# greeting["Mr. Steve Austin"] #=> "Hello sir!"
|
16
|
+
# greeting["Mrs. Steve Austin"] #=> "Evening, madame."
|
17
|
+
#
|
18
|
+
# Note: The Rash is automatically optimized every 500 accesses
|
19
|
+
# (Regexps get sorted by how often they get matched).
|
20
|
+
# If this is too low or too high, you can tune it by
|
21
|
+
# setting: `rash.optimize_every = n`
|
22
|
+
#
|
23
|
+
class Rash
|
24
|
+
attr_accessor :optimize_every
|
25
|
+
|
26
|
+
def initialize(initial = {})
|
27
|
+
@hash = {}
|
28
|
+
@regexes = []
|
29
|
+
@ranges = []
|
30
|
+
@regex_counts = Hash.new(0)
|
31
|
+
@optimize_every = 500
|
32
|
+
@lookups = 0
|
33
|
+
|
34
|
+
update(initial)
|
35
|
+
end
|
36
|
+
|
37
|
+
def update(other)
|
38
|
+
other.each do |key, value|
|
39
|
+
self[key] = value
|
40
|
+
end
|
41
|
+
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
def []=(key, value)
|
46
|
+
case key
|
47
|
+
when Regexp
|
48
|
+
# key = normalize_regex(key) # this used to just do: /#{regexp}/
|
49
|
+
@regexes << key
|
50
|
+
when Range
|
51
|
+
@ranges << key
|
52
|
+
end
|
53
|
+
@hash[key] = value
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# Return the first thing that matches the key.
|
58
|
+
#
|
59
|
+
def [](key)
|
60
|
+
all(key).first
|
61
|
+
end
|
62
|
+
|
63
|
+
#
|
64
|
+
# Return everything that matches the query.
|
65
|
+
#
|
66
|
+
def all(query)
|
67
|
+
return to_enum(:all, query) unless block_given?
|
68
|
+
|
69
|
+
if @hash.include? query
|
70
|
+
yield @hash[query]
|
71
|
+
return
|
72
|
+
end
|
73
|
+
|
74
|
+
case query
|
75
|
+
when String
|
76
|
+
optimize_if_necessary!
|
77
|
+
|
78
|
+
# see if any of the regexps match the string
|
79
|
+
@regexes.each do |regex|
|
80
|
+
match = regex.match(query)
|
81
|
+
if match
|
82
|
+
@regex_counts[regex] += 1
|
83
|
+
value = @hash[regex]
|
84
|
+
if value.respond_to? :call
|
85
|
+
yield value.call(match)
|
86
|
+
else
|
87
|
+
yield value
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
when Integer
|
93
|
+
# see if any of the ranges match the integer
|
94
|
+
@ranges.each do |range|
|
95
|
+
yield @hash[range] if range.include? query
|
96
|
+
end
|
97
|
+
|
98
|
+
when Regexp
|
99
|
+
# Reverse operation: `rash[/regexp/]` returns all the hash's string keys which match the regexp
|
100
|
+
@hash.each do |key, val|
|
101
|
+
yield val if key.is_a?(String) && query =~ key
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def method_missing(*args, &block)
|
107
|
+
@hash.send(*args, &block)
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def optimize_if_necessary!
|
113
|
+
if (@lookups += 1) >= @optimize_every
|
114
|
+
@regexes = @regex_counts.sort_by { |regex, count| -count }.map { |regex, count| regex }
|
115
|
+
@lookups = 0
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
data/lib/hashie/trash.rb
CHANGED
@@ -8,7 +8,6 @@ module Hashie
|
|
8
8
|
# such as a Java api, where the keys are named differently from how we would
|
9
9
|
# in Ruby.
|
10
10
|
class Trash < Dash
|
11
|
-
|
12
11
|
# Defines a property on the Trash. Options are as follows:
|
13
12
|
#
|
14
13
|
# * <tt>:default</tt> - Specify a default value for this property, to be
|
@@ -20,33 +19,31 @@ module Hashie
|
|
20
19
|
def self.property(property_name, options = {})
|
21
20
|
super
|
22
21
|
|
22
|
+
options[:from] = options[:from].to_sym if options[:from]
|
23
|
+
property_name = property_name.to_sym
|
24
|
+
|
23
25
|
if options[:from]
|
24
|
-
if property_name
|
25
|
-
|
26
|
+
if property_name == options[:from]
|
27
|
+
fail ArgumentError, "Property name (#{property_name}) and :from option must not be the same"
|
28
|
+
end
|
29
|
+
|
30
|
+
translations[options[:from].to_sym] = property_name.to_sym
|
31
|
+
|
32
|
+
define_method "#{options[:from]}=" do |val|
|
33
|
+
with = options[:with] || options[:transform_with]
|
34
|
+
self[property_name.to_sym] = with.respond_to?(:call) ? with.call(val) : val
|
26
35
|
end
|
27
|
-
|
28
|
-
if options[:
|
29
|
-
|
30
|
-
define_method "#{options[:from]}=" do |val|
|
31
|
-
self[property_name.to_sym] = options[:with].call(val)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
else
|
35
|
-
class_eval <<-RUBY
|
36
|
-
def #{options[:from]}=(val)
|
37
|
-
self[:#{property_name}] = val
|
38
|
-
end
|
39
|
-
RUBY
|
36
|
+
else
|
37
|
+
if options[:transform_with].respond_to? :call
|
38
|
+
transforms[property_name.to_sym] = options[:transform_with]
|
40
39
|
end
|
41
|
-
elsif options[:transform_with].respond_to? :call
|
42
|
-
transforms[property_name.to_sym] = options[:transform_with]
|
43
40
|
end
|
44
41
|
end
|
45
42
|
|
46
43
|
# Set a value on the Dash in a Hash-like way. Only works
|
47
44
|
# on pre-existing properties.
|
48
45
|
def []=(property, value)
|
49
|
-
if self.class.translations.
|
46
|
+
if self.class.translations.key? property.to_sym
|
50
47
|
send("#{property}=", value)
|
51
48
|
elsif self.class.transforms.key? property.to_sym
|
52
49
|
super property, self.class.transforms[property.to_sym].call(value)
|
@@ -55,10 +52,22 @@ module Hashie
|
|
55
52
|
end
|
56
53
|
end
|
57
54
|
|
55
|
+
def self.permitted_input_keys
|
56
|
+
@permitted_input_keys ||= properties.map { |property| inverse_translations.fetch property, property }
|
57
|
+
end
|
58
|
+
|
58
59
|
private
|
59
60
|
|
61
|
+
def self.properties
|
62
|
+
@properties ||= []
|
63
|
+
end
|
64
|
+
|
60
65
|
def self.translations
|
61
|
-
@translations ||=
|
66
|
+
@translations ||= {}
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.inverse_translations
|
70
|
+
@inverse_translations ||= Hash[translations.map(&:reverse)]
|
62
71
|
end
|
63
72
|
|
64
73
|
def self.transforms
|
@@ -69,7 +78,7 @@ module Hashie
|
|
69
78
|
#
|
70
79
|
def property_exists?(property)
|
71
80
|
unless self.class.property?(property.to_sym)
|
72
|
-
|
81
|
+
fail NoMethodError, "The property '#{property}' is not defined for this Trash."
|
73
82
|
end
|
74
83
|
true
|
75
84
|
end
|
@@ -79,7 +88,7 @@ module Hashie
|
|
79
88
|
# Deletes any keys that have a translation
|
80
89
|
def initialize_attributes(attributes)
|
81
90
|
return unless attributes
|
82
|
-
attributes_copy = attributes.dup.delete_if do |k,v|
|
91
|
+
attributes_copy = attributes.dup.delete_if do |k, v|
|
83
92
|
if self.class.translations.include?(k.to_sym)
|
84
93
|
self[k] = v
|
85
94
|
true
|