active_hash 3.1.0 → 3.2.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 +4 -4
- data/CHANGELOG.md +353 -0
- data/README.md +48 -15
- data/active_hash.gemspec +9 -2
- data/lib/active_file/base.rb +13 -6
- data/lib/active_file/hash_and_array_files.rb +1 -1
- data/lib/active_hash/base.rb +42 -55
- data/lib/active_hash/condition.rb +44 -0
- data/lib/active_hash/conditions.rb +21 -0
- data/lib/active_hash/relation.rb +130 -86
- data/lib/active_hash/version.rb +1 -1
- data/lib/active_hash.rb +2 -0
- data/lib/active_yaml/aliases.rb +11 -6
- data/lib/active_yaml/base.rb +16 -2
- data/lib/associations/associations.rb +27 -19
- data/lib/associations/reflection_extensions.rb +25 -0
- metadata +16 -10
- data/CHANGELOG +0 -225
data/lib/active_hash/base.rb
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
module ActiveHash
|
|
2
|
-
|
|
3
2
|
class RecordNotFound < StandardError
|
|
3
|
+
attr_reader :model, :primary_key, :id
|
|
4
|
+
|
|
5
|
+
def initialize(message = nil, model = nil, primary_key = nil, id = nil)
|
|
6
|
+
@primary_key = primary_key
|
|
7
|
+
@model = model
|
|
8
|
+
@id = id
|
|
9
|
+
|
|
10
|
+
super(message)
|
|
11
|
+
end
|
|
4
12
|
end
|
|
5
13
|
|
|
6
14
|
class ReservedFieldError < StandardError
|
|
@@ -13,50 +21,7 @@ module ActiveHash
|
|
|
13
21
|
end
|
|
14
22
|
|
|
15
23
|
class Base
|
|
16
|
-
|
|
17
|
-
class_attribute :_data, :dirty, :default_attributes
|
|
18
|
-
|
|
19
|
-
class WhereChain
|
|
20
|
-
def initialize(scope)
|
|
21
|
-
@scope = scope
|
|
22
|
-
@records = @scope.all
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def not(options)
|
|
26
|
-
return @scope if options.blank?
|
|
27
|
-
|
|
28
|
-
# use index if searching by id
|
|
29
|
-
if options.key?(:id) || options.key?("id")
|
|
30
|
-
ids = @scope.pluck(:id) - Array.wrap(options.delete(:id) || options.delete("id"))
|
|
31
|
-
candidates = ids.map { |id| @scope.find_by_id(id) }.compact
|
|
32
|
-
end
|
|
33
|
-
return candidates if options.blank?
|
|
34
|
-
|
|
35
|
-
filtered_records = (candidates || @records || []).reject do |record|
|
|
36
|
-
match_options?(record, options)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
ActiveHash::Relation.new(@scope.klass, filtered_records, {})
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def match_options?(record, options)
|
|
43
|
-
options.all? do |col, match|
|
|
44
|
-
if match.kind_of?(Array)
|
|
45
|
-
match.any? { |v| normalize(v) == normalize(record[col]) }
|
|
46
|
-
else
|
|
47
|
-
normalize(record[col]) == normalize(match)
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
private :match_options?
|
|
53
|
-
|
|
54
|
-
def normalize(v)
|
|
55
|
-
v.respond_to?(:to_sym) ? v.to_sym : v
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
private :normalize
|
|
59
|
-
end
|
|
24
|
+
class_attribute :_data, :dirty, :default_attributes, :scopes
|
|
60
25
|
|
|
61
26
|
if Object.const_defined?(:ActiveModel)
|
|
62
27
|
extend ActiveModel::Naming
|
|
@@ -120,9 +85,17 @@ module ActiveHash
|
|
|
120
85
|
end
|
|
121
86
|
end
|
|
122
87
|
|
|
123
|
-
def exists?(
|
|
124
|
-
if
|
|
125
|
-
record_index[
|
|
88
|
+
def exists?(args = nil)
|
|
89
|
+
if args.respond_to?(:id)
|
|
90
|
+
record_index[args.id.to_s].present?
|
|
91
|
+
elsif args == false
|
|
92
|
+
false
|
|
93
|
+
elsif args.nil?
|
|
94
|
+
all.present?
|
|
95
|
+
elsif args.is_a?(Hash)
|
|
96
|
+
all.where(args).present?
|
|
97
|
+
else
|
|
98
|
+
all.where(id: args.to_i).present?
|
|
126
99
|
end
|
|
127
100
|
end
|
|
128
101
|
|
|
@@ -137,7 +110,7 @@ module ActiveHash
|
|
|
137
110
|
end
|
|
138
111
|
|
|
139
112
|
def next_id
|
|
140
|
-
max_record =
|
|
113
|
+
max_record = all_in_process.max { |a, b| a.id <=> b.id }
|
|
141
114
|
if max_record.nil?
|
|
142
115
|
1
|
|
143
116
|
elsif max_record.id.is_a?(Numeric)
|
|
@@ -145,6 +118,11 @@ module ActiveHash
|
|
|
145
118
|
end
|
|
146
119
|
end
|
|
147
120
|
|
|
121
|
+
def all_in_process
|
|
122
|
+
all
|
|
123
|
+
end
|
|
124
|
+
private :all_in_process
|
|
125
|
+
|
|
148
126
|
def record_index
|
|
149
127
|
@record_index ||= {}
|
|
150
128
|
end
|
|
@@ -185,10 +163,12 @@ module ActiveHash
|
|
|
185
163
|
end
|
|
186
164
|
|
|
187
165
|
def all(options = {})
|
|
188
|
-
ActiveHash::Relation.new(self, @records || []
|
|
166
|
+
relation = ActiveHash::Relation.new(self, @records || [])
|
|
167
|
+
relation = relation.where!(options[:conditions]) if options[:conditions]
|
|
168
|
+
relation
|
|
189
169
|
end
|
|
190
170
|
|
|
191
|
-
delegate :where, :find, :find_by, :find_by!, :find_by_id, :count, :pluck, :first, :last, :order, to: :all
|
|
171
|
+
delegate :where, :find, :find_by, :find_by!, :find_by_id, :count, :pluck, :ids, :pick, :first, :last, :order, to: :all
|
|
192
172
|
|
|
193
173
|
def transaction
|
|
194
174
|
yield
|
|
@@ -217,7 +197,7 @@ module ActiveHash
|
|
|
217
197
|
validate_field(field_name)
|
|
218
198
|
field_names << field_name
|
|
219
199
|
|
|
220
|
-
add_default_value(field_name, options[:default]) if options
|
|
200
|
+
add_default_value(field_name, options[:default]) if options.key?(:default)
|
|
221
201
|
define_getter_method(field_name, options[:default])
|
|
222
202
|
define_setter_method(field_name)
|
|
223
203
|
define_interrogator_method(field_name)
|
|
@@ -388,10 +368,13 @@ module ActiveHash
|
|
|
388
368
|
end
|
|
389
369
|
|
|
390
370
|
private :mark_clean
|
|
391
|
-
|
|
371
|
+
|
|
392
372
|
def scope(name, body)
|
|
393
373
|
raise ArgumentError, 'body needs to be callable' unless body.respond_to?(:call)
|
|
394
|
-
|
|
374
|
+
|
|
375
|
+
self.scopes ||= {}
|
|
376
|
+
self.scopes[name] = body
|
|
377
|
+
|
|
395
378
|
the_meta_class.instance_eval do
|
|
396
379
|
define_method(name) do |*args|
|
|
397
380
|
instance_exec(*args, &body)
|
|
@@ -472,7 +455,11 @@ module ActiveHash
|
|
|
472
455
|
when new_record?
|
|
473
456
|
"#{self.class.cache_key}/new"
|
|
474
457
|
when timestamp = self[:updated_at]
|
|
475
|
-
|
|
458
|
+
if ActiveSupport::VERSION::MAJOR < 7
|
|
459
|
+
"#{self.class.cache_key}/#{id}-#{timestamp.to_s(:number)}"
|
|
460
|
+
else
|
|
461
|
+
"#{self.class.cache_key}/#{id}-#{timestamp.to_fs(:number)}"
|
|
462
|
+
end
|
|
476
463
|
else
|
|
477
464
|
"#{self.class.cache_key}/#{id}"
|
|
478
465
|
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
class ActiveHash::Relation::Condition
|
|
2
|
+
attr_reader :constraints, :inverted
|
|
3
|
+
|
|
4
|
+
def initialize(constraints)
|
|
5
|
+
@constraints = constraints
|
|
6
|
+
@inverted = false
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def invert!
|
|
10
|
+
@inverted = !inverted
|
|
11
|
+
|
|
12
|
+
self
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def matches?(record)
|
|
16
|
+
match = begin
|
|
17
|
+
return true unless constraints
|
|
18
|
+
|
|
19
|
+
expectation_method = inverted ? :any? : :all?
|
|
20
|
+
|
|
21
|
+
constraints.send(expectation_method) do |attribute, expected|
|
|
22
|
+
value = record.public_send(attribute)
|
|
23
|
+
|
|
24
|
+
matches_value?(value, expected)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
inverted ? !match : match
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def matches_value?(value, comparison)
|
|
34
|
+
return comparison.any? { |v| matches_value?(value, v) } if comparison.is_a?(Array)
|
|
35
|
+
return comparison.cover?(value) if comparison.is_a?(Range)
|
|
36
|
+
return comparison.match?(value) if comparison.is_a?(Regexp)
|
|
37
|
+
|
|
38
|
+
normalize(value) == normalize(comparison)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def normalize(value)
|
|
42
|
+
value.respond_to?(:to_s) ? value.to_s : value
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class ActiveHash::Relation::Conditions
|
|
2
|
+
attr_reader :conditions
|
|
3
|
+
|
|
4
|
+
delegate :<<, :map, to: :conditions
|
|
5
|
+
|
|
6
|
+
def initialize(conditions = [])
|
|
7
|
+
@conditions = conditions
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def matches?(record)
|
|
11
|
+
conditions.all? do |condition|
|
|
12
|
+
condition.matches?(record)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.wrap(conditions)
|
|
17
|
+
return conditions if conditions.is_a?(self)
|
|
18
|
+
|
|
19
|
+
new(conditions)
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/active_hash/relation.rb
CHANGED
|
@@ -1,44 +1,109 @@
|
|
|
1
1
|
module ActiveHash
|
|
2
2
|
class Relation
|
|
3
3
|
include Enumerable
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
delegate :each, to: :records # Make Enumerable work
|
|
6
6
|
delegate :equal?, :==, :===, :eql?, :sort!, to: :records
|
|
7
7
|
delegate :empty?, :length, :first, :second, :third, :last, to: :records
|
|
8
8
|
delegate :sample, to: :records
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
|
|
10
|
+
attr_reader :conditions, :order_values, :klass, :all_records
|
|
11
|
+
|
|
12
|
+
def initialize(klass, all_records, conditions = nil, order_values = nil)
|
|
11
13
|
self.klass = klass
|
|
12
14
|
self.all_records = all_records
|
|
13
|
-
self.
|
|
14
|
-
self.
|
|
15
|
+
self.conditions = Conditions.wrap(conditions || [])
|
|
16
|
+
self.order_values = order_values || []
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def where(conditions_hash = :chain)
|
|
20
|
+
return WhereChain.new(self) if conditions_hash == :chain
|
|
21
|
+
|
|
22
|
+
spawn.where!(conditions_hash)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
class WhereChain
|
|
26
|
+
attr_reader :relation
|
|
27
|
+
|
|
28
|
+
def initialize(relation)
|
|
29
|
+
@relation = relation
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def not(conditions_hash)
|
|
33
|
+
relation.conditions << Condition.new(conditions_hash).invert!
|
|
34
|
+
relation
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def order(*options)
|
|
39
|
+
spawn.order!(*options)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def reorder(*options)
|
|
43
|
+
spawn.reorder!(*options)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def where!(conditions_hash, inverted = false)
|
|
47
|
+
self.conditions << Condition.new(conditions_hash)
|
|
48
|
+
self
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def invert_where
|
|
52
|
+
spawn.invert_where!
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def invert_where!
|
|
56
|
+
conditions.map(&:invert!)
|
|
57
|
+
self
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def spawn
|
|
61
|
+
self.class.new(klass, all_records, conditions, order_values)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def order!(*options)
|
|
65
|
+
check_if_method_has_arguments!(:order, options)
|
|
66
|
+
self.order_values += preprocess_order_args(options)
|
|
15
67
|
self
|
|
16
68
|
end
|
|
17
|
-
|
|
18
|
-
def
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
self.
|
|
22
|
-
|
|
69
|
+
|
|
70
|
+
def reorder!(*options)
|
|
71
|
+
check_if_method_has_arguments!(:order, options)
|
|
72
|
+
|
|
73
|
+
self.order_values = preprocess_order_args(options)
|
|
74
|
+
@records = apply_order_values(records, order_values)
|
|
75
|
+
|
|
76
|
+
self
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def records
|
|
80
|
+
@records ||= begin
|
|
81
|
+
filtered_records = apply_conditions(all_records, conditions)
|
|
82
|
+
ordered_records = apply_order_values(filtered_records, order_values) # rubocop:disable Lint/UselessAssignment
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def reload
|
|
87
|
+
@records = nil # Reset records
|
|
23
88
|
self
|
|
24
89
|
end
|
|
25
|
-
|
|
90
|
+
|
|
26
91
|
def all(options = {})
|
|
27
|
-
if options.
|
|
92
|
+
if options.key?(:conditions)
|
|
28
93
|
where(options[:conditions])
|
|
29
94
|
else
|
|
30
95
|
where({})
|
|
31
96
|
end
|
|
32
97
|
end
|
|
33
|
-
|
|
98
|
+
|
|
34
99
|
def find_by(options)
|
|
35
100
|
where(options).first
|
|
36
101
|
end
|
|
37
102
|
|
|
38
103
|
def find_by!(options)
|
|
39
|
-
find_by(options) || (raise RecordNotFound.new("Couldn't find #{klass.name}"))
|
|
104
|
+
find_by(options) || (raise RecordNotFound.new("Couldn't find #{klass.name}", klass.name))
|
|
40
105
|
end
|
|
41
|
-
|
|
106
|
+
|
|
42
107
|
def find(id = nil, *args, &block)
|
|
43
108
|
case id
|
|
44
109
|
when :all
|
|
@@ -48,101 +113,76 @@ module ActiveHash
|
|
|
48
113
|
when Array
|
|
49
114
|
id.map { |i| find(i) }
|
|
50
115
|
when nil
|
|
51
|
-
raise RecordNotFound.new("Couldn't find #{klass.name} without an ID") unless block_given?
|
|
116
|
+
raise RecordNotFound.new("Couldn't find #{klass.name} without an ID", klass.name, "id") unless block_given?
|
|
52
117
|
records.find(&block) # delegate to Enumerable#find if a block is given
|
|
53
118
|
else
|
|
54
119
|
find_by_id(id) || begin
|
|
55
|
-
raise RecordNotFound.new("Couldn't find #{klass.name} with ID=#{id}")
|
|
120
|
+
raise RecordNotFound.new("Couldn't find #{klass.name} with ID=#{id}", klass.name, "id", id)
|
|
56
121
|
end
|
|
57
122
|
end
|
|
58
123
|
end
|
|
59
|
-
|
|
124
|
+
|
|
60
125
|
def find_by_id(id)
|
|
61
126
|
index = klass.send(:record_index)[id.to_s] # TODO: Make index in Base publicly readable instead of using send?
|
|
62
|
-
|
|
127
|
+
return unless index
|
|
128
|
+
|
|
129
|
+
record = all_records[index]
|
|
130
|
+
record if conditions.matches?(record)
|
|
63
131
|
end
|
|
64
|
-
|
|
132
|
+
|
|
65
133
|
def count
|
|
66
134
|
length
|
|
67
135
|
end
|
|
68
|
-
|
|
69
|
-
def
|
|
70
|
-
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def reload
|
|
74
|
-
@records = filter_all_records_by_query_hash
|
|
136
|
+
|
|
137
|
+
def size
|
|
138
|
+
length
|
|
75
139
|
end
|
|
76
140
|
|
|
77
|
-
def
|
|
78
|
-
|
|
79
|
-
relation = where({})
|
|
80
|
-
return relation if options.blank?
|
|
141
|
+
def pluck(*column_names)
|
|
142
|
+
symbolized_column_names = column_names.map(&:to_sym)
|
|
81
143
|
|
|
82
|
-
|
|
83
|
-
|
|
144
|
+
if symbolized_column_names.length == 1
|
|
145
|
+
column_name = symbolized_column_names.first
|
|
146
|
+
all.map { |record| record[column_name] }
|
|
147
|
+
else
|
|
148
|
+
all.map do |record|
|
|
149
|
+
symbolized_column_names.map { |column_name| record[column_name] }
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
84
153
|
|
|
85
|
-
|
|
154
|
+
def ids
|
|
155
|
+
pluck(:id)
|
|
156
|
+
end
|
|
86
157
|
|
|
87
|
-
|
|
158
|
+
def pick(*column_names)
|
|
159
|
+
pluck(*column_names).first
|
|
88
160
|
end
|
|
89
|
-
|
|
161
|
+
|
|
90
162
|
def to_ary
|
|
91
163
|
records.dup
|
|
92
164
|
end
|
|
93
|
-
|
|
94
165
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
private
|
|
98
|
-
|
|
99
|
-
attr_writer :query_hash, :klass, :all_records, :records_dirty
|
|
100
|
-
|
|
101
|
-
def records
|
|
102
|
-
if @records.nil? || records_dirty
|
|
103
|
-
reload
|
|
104
|
-
else
|
|
105
|
-
@records
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def filter_all_records_by_query_hash
|
|
110
|
-
self.records_dirty = false
|
|
111
|
-
return all_records if query_hash.blank?
|
|
112
|
-
|
|
113
|
-
# use index if searching by id
|
|
114
|
-
if query_hash.key?(:id) || query_hash.key?("id")
|
|
115
|
-
ids = (query_hash.delete(:id) || query_hash.delete("id"))
|
|
116
|
-
ids = range_to_array(ids) if ids.is_a?(Range)
|
|
117
|
-
candidates = Array.wrap(ids).map { |id| klass.find_by_id(id) }.compact
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
return candidates if query_hash.blank?
|
|
166
|
+
def method_missing(method_name, *args)
|
|
167
|
+
return super unless klass.scopes.key?(method_name)
|
|
121
168
|
|
|
122
|
-
(
|
|
123
|
-
match_options?(record, query_hash)
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
def match_options?(record, options)
|
|
128
|
-
options.all? do |col, match|
|
|
129
|
-
if match.kind_of?(Array)
|
|
130
|
-
match.any? { |v| normalize(v) == normalize(record[col]) }
|
|
131
|
-
else
|
|
132
|
-
normalize(record[col]) == normalize(match)
|
|
133
|
-
end
|
|
134
|
-
end
|
|
169
|
+
instance_exec(*args, &klass.scopes[method_name])
|
|
135
170
|
end
|
|
136
171
|
|
|
137
|
-
def
|
|
138
|
-
|
|
172
|
+
def respond_to_missing?(method_name, include_private = false)
|
|
173
|
+
klass.scopes.key?(method_name) || super
|
|
139
174
|
end
|
|
140
|
-
|
|
141
|
-
def range_to_array(range)
|
|
142
|
-
return range.to_a unless range.end.nil?
|
|
143
175
|
|
|
144
|
-
|
|
145
|
-
|
|
176
|
+
private
|
|
177
|
+
|
|
178
|
+
attr_writer :conditions, :order_values, :klass, :all_records
|
|
179
|
+
|
|
180
|
+
def apply_conditions(records, conditions)
|
|
181
|
+
return records if conditions.blank?
|
|
182
|
+
|
|
183
|
+
records.select do |record|
|
|
184
|
+
conditions.matches?(record)
|
|
185
|
+
end
|
|
146
186
|
end
|
|
147
187
|
|
|
148
188
|
def check_if_method_has_arguments!(method_name, args)
|
|
@@ -160,7 +200,9 @@ module ActiveHash
|
|
|
160
200
|
ary.map! { |e| e.split(/\W+/) }.reverse!
|
|
161
201
|
end
|
|
162
202
|
|
|
163
|
-
def
|
|
203
|
+
def apply_order_values(records, args)
|
|
204
|
+
ordered_records = records.dup
|
|
205
|
+
|
|
164
206
|
args.each do |arg|
|
|
165
207
|
field, dir = if arg.is_a?(Hash)
|
|
166
208
|
arg.to_a.flatten.map(&:to_sym)
|
|
@@ -170,7 +212,7 @@ module ActiveHash
|
|
|
170
212
|
arg.to_sym
|
|
171
213
|
end
|
|
172
214
|
|
|
173
|
-
|
|
215
|
+
ordered_records.sort! do |a, b|
|
|
174
216
|
if dir.present? && dir.to_sym.upcase.equal?(:DESC)
|
|
175
217
|
b[field] <=> a[field]
|
|
176
218
|
else
|
|
@@ -178,6 +220,8 @@ module ActiveHash
|
|
|
178
220
|
end
|
|
179
221
|
end
|
|
180
222
|
end
|
|
223
|
+
|
|
224
|
+
ordered_records
|
|
181
225
|
end
|
|
182
226
|
end
|
|
183
227
|
end
|
data/lib/active_hash/version.rb
CHANGED
data/lib/active_hash.rb
CHANGED
data/lib/active_yaml/aliases.rb
CHANGED
|
@@ -5,6 +5,8 @@ module ActiveYaml
|
|
|
5
5
|
base.extend(ClassMethods)
|
|
6
6
|
end
|
|
7
7
|
|
|
8
|
+
ALIAS_KEY_REGEXP = /^\//.freeze
|
|
9
|
+
|
|
8
10
|
module ClassMethods
|
|
9
11
|
|
|
10
12
|
def insert(record)
|
|
@@ -12,16 +14,19 @@ module ActiveYaml
|
|
|
12
14
|
end
|
|
13
15
|
|
|
14
16
|
def raw_data
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
d = super
|
|
18
|
+
if d.kind_of?(Array)
|
|
19
|
+
d.reject do |h|
|
|
20
|
+
h.keys.any? { |k| k.match(ALIAS_KEY_REGEXP) }
|
|
21
|
+
end
|
|
22
|
+
else
|
|
23
|
+
d.reject do |k, v|
|
|
24
|
+
v.kind_of?(Hash) && k.match(ALIAS_KEY_REGEXP)
|
|
25
|
+
end
|
|
17
26
|
end
|
|
18
27
|
end
|
|
19
28
|
|
|
20
29
|
end
|
|
21
|
-
|
|
22
|
-
def initialize(attributes={})
|
|
23
|
-
super unless attributes.keys.index { |k| k.to_s.match(/^\//i) }
|
|
24
|
-
end
|
|
25
30
|
end
|
|
26
31
|
|
|
27
32
|
end
|
data/lib/active_yaml/base.rb
CHANGED
|
@@ -4,12 +4,16 @@ module ActiveYaml
|
|
|
4
4
|
|
|
5
5
|
class Base < ActiveFile::Base
|
|
6
6
|
extend ActiveFile::HashAndArrayFiles
|
|
7
|
+
|
|
8
|
+
cattr_accessor :process_erb, instance_accessor: false
|
|
9
|
+
@@process_erb = true
|
|
10
|
+
|
|
7
11
|
class << self
|
|
8
12
|
def load_file
|
|
9
13
|
if (data = raw_data).is_a?(Array)
|
|
10
14
|
data
|
|
11
15
|
elsif data.respond_to?(:values)
|
|
12
|
-
data.
|
|
16
|
+
data.map{ |key, value| {"key" => key}.merge(value) }
|
|
13
17
|
end
|
|
14
18
|
end
|
|
15
19
|
|
|
@@ -18,9 +22,19 @@ module ActiveYaml
|
|
|
18
22
|
end
|
|
19
23
|
|
|
20
24
|
private
|
|
25
|
+
if Psych::VERSION >= "4.0.0"
|
|
21
26
|
def load_path(path)
|
|
22
|
-
|
|
27
|
+
result = File.read(path)
|
|
28
|
+
result = ERB.new(result).result if process_erb
|
|
29
|
+
YAML.unsafe_load(result)
|
|
23
30
|
end
|
|
31
|
+
else
|
|
32
|
+
def load_path(path)
|
|
33
|
+
result = File.read(path)
|
|
34
|
+
result = ERB.new(result).result if process_erb
|
|
35
|
+
YAML.load(result)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
24
38
|
end
|
|
25
39
|
end
|
|
26
40
|
end
|