active_hash 3.0.0 → 3.2.1
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 +366 -0
- data/README.md +62 -19
- 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 +175 -72
- 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 +30 -19
- data/lib/associations/reflection_extensions.rb +25 -0
- metadata +13 -7
- data/CHANGELOG +0 -219
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, 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.read_attribute(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,114 @@
|
|
|
1
1
|
module ActiveHash
|
|
2
2
|
class Relation
|
|
3
3
|
include Enumerable
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
delegate :each, to: :records # Make Enumerable work
|
|
6
|
-
delegate :equal?, :==, :===, :eql?, to: :records
|
|
6
|
+
delegate :equal?, :==, :===, :eql?, :sort!, to: :records
|
|
7
7
|
delegate :empty?, :length, :first, :second, :third, :last, to: :records
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
delegate :sample, to: :records
|
|
9
|
+
|
|
10
|
+
attr_reader :conditions, :order_values, :klass, :all_records
|
|
11
|
+
|
|
12
|
+
def initialize(klass, all_records, conditions = nil, order_values = nil)
|
|
10
13
|
self.klass = klass
|
|
11
14
|
self.all_records = all_records
|
|
12
|
-
self.
|
|
13
|
-
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
|
+
def pretty_print(pp)
|
|
26
|
+
pp.pp(entries.to_ary)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class WhereChain
|
|
30
|
+
attr_reader :relation
|
|
31
|
+
|
|
32
|
+
def initialize(relation)
|
|
33
|
+
@relation = relation
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def not(conditions_hash)
|
|
37
|
+
relation.conditions << Condition.new(conditions_hash).invert!
|
|
38
|
+
relation
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def order(*options)
|
|
43
|
+
spawn.order!(*options)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def reorder(*options)
|
|
47
|
+
spawn.reorder!(*options)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def where!(conditions_hash, inverted = false)
|
|
51
|
+
self.conditions << Condition.new(conditions_hash)
|
|
14
52
|
self
|
|
15
53
|
end
|
|
16
|
-
|
|
17
|
-
def
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
54
|
+
|
|
55
|
+
def invert_where
|
|
56
|
+
spawn.invert_where!
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def invert_where!
|
|
60
|
+
conditions.map(&:invert!)
|
|
61
|
+
self
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def spawn
|
|
65
|
+
self.class.new(klass, all_records, conditions, order_values)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def order!(*options)
|
|
69
|
+
check_if_method_has_arguments!(:order, options)
|
|
70
|
+
self.order_values += preprocess_order_args(options)
|
|
71
|
+
self
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def reorder!(*options)
|
|
75
|
+
check_if_method_has_arguments!(:order, options)
|
|
76
|
+
|
|
77
|
+
self.order_values = preprocess_order_args(options)
|
|
78
|
+
@records = apply_order_values(records, order_values)
|
|
79
|
+
|
|
22
80
|
self
|
|
23
81
|
end
|
|
24
|
-
|
|
82
|
+
|
|
83
|
+
def records
|
|
84
|
+
@records ||= begin
|
|
85
|
+
filtered_records = apply_conditions(all_records, conditions)
|
|
86
|
+
ordered_records = apply_order_values(filtered_records, order_values) # rubocop:disable Lint/UselessAssignment
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def reload
|
|
91
|
+
@records = nil # Reset records
|
|
92
|
+
self
|
|
93
|
+
end
|
|
94
|
+
|
|
25
95
|
def all(options = {})
|
|
26
|
-
if options.
|
|
96
|
+
if options.key?(:conditions)
|
|
27
97
|
where(options[:conditions])
|
|
28
98
|
else
|
|
29
99
|
where({})
|
|
30
100
|
end
|
|
31
101
|
end
|
|
32
|
-
|
|
102
|
+
|
|
33
103
|
def find_by(options)
|
|
34
104
|
where(options).first
|
|
35
105
|
end
|
|
36
106
|
|
|
37
107
|
def find_by!(options)
|
|
38
|
-
find_by(options) || (raise RecordNotFound.new("Couldn't find #{klass.name}"))
|
|
108
|
+
find_by(options) || (raise RecordNotFound.new("Couldn't find #{klass.name}", klass.name))
|
|
39
109
|
end
|
|
40
|
-
|
|
41
|
-
def find(id, *args)
|
|
110
|
+
|
|
111
|
+
def find(id = nil, *args, &block)
|
|
42
112
|
case id
|
|
43
113
|
when :all
|
|
44
114
|
all
|
|
@@ -47,82 +117,115 @@ module ActiveHash
|
|
|
47
117
|
when Array
|
|
48
118
|
id.map { |i| find(i) }
|
|
49
119
|
when nil
|
|
50
|
-
raise RecordNotFound.new("Couldn't find #{klass.name} without an ID")
|
|
120
|
+
raise RecordNotFound.new("Couldn't find #{klass.name} without an ID", klass.name, "id") unless block_given?
|
|
121
|
+
records.find(&block) # delegate to Enumerable#find if a block is given
|
|
51
122
|
else
|
|
52
123
|
find_by_id(id) || begin
|
|
53
|
-
raise RecordNotFound.new("Couldn't find #{klass.name} with ID=#{id}")
|
|
124
|
+
raise RecordNotFound.new("Couldn't find #{klass.name} with ID=#{id}", klass.name, "id", id)
|
|
54
125
|
end
|
|
55
126
|
end
|
|
56
127
|
end
|
|
57
|
-
|
|
128
|
+
|
|
58
129
|
def find_by_id(id)
|
|
59
130
|
index = klass.send(:record_index)[id.to_s] # TODO: Make index in Base publicly readable instead of using send?
|
|
60
|
-
|
|
131
|
+
return unless index
|
|
132
|
+
|
|
133
|
+
record = all_records[index]
|
|
134
|
+
record if conditions.matches?(record)
|
|
61
135
|
end
|
|
62
|
-
|
|
136
|
+
|
|
63
137
|
def count
|
|
64
138
|
length
|
|
65
139
|
end
|
|
66
|
-
|
|
67
|
-
def
|
|
68
|
-
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def reload
|
|
72
|
-
@records = filter_all_records_by_query_hash
|
|
140
|
+
|
|
141
|
+
def size
|
|
142
|
+
length
|
|
73
143
|
end
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def records
|
|
82
|
-
if @records.nil? || records_dirty
|
|
83
|
-
reload
|
|
144
|
+
|
|
145
|
+
def pluck(*column_names)
|
|
146
|
+
symbolized_column_names = column_names.map(&:to_sym)
|
|
147
|
+
|
|
148
|
+
if symbolized_column_names.length == 1
|
|
149
|
+
column_name = symbolized_column_names.first
|
|
150
|
+
all.map { |record| record[column_name] }
|
|
84
151
|
else
|
|
85
|
-
|
|
152
|
+
all.map do |record|
|
|
153
|
+
symbolized_column_names.map { |column_name| record[column_name] }
|
|
154
|
+
end
|
|
86
155
|
end
|
|
87
156
|
end
|
|
88
|
-
|
|
89
|
-
def filter_all_records_by_query_hash
|
|
90
|
-
self.records_dirty = false
|
|
91
|
-
return all_records if query_hash.blank?
|
|
92
|
-
|
|
93
|
-
# use index if searching by id
|
|
94
|
-
if query_hash.key?(:id) || query_hash.key?("id")
|
|
95
|
-
ids = (query_hash.delete(:id) || query_hash.delete("id"))
|
|
96
|
-
ids = range_to_array(ids) if ids.is_a?(Range)
|
|
97
|
-
candidates = Array.wrap(ids).map { |id| klass.find_by_id(id) }.compact
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
return candidates if query_hash.blank?
|
|
101
157
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
end
|
|
158
|
+
def ids
|
|
159
|
+
pluck(:id)
|
|
105
160
|
end
|
|
106
|
-
|
|
107
|
-
def
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
161
|
+
|
|
162
|
+
def pick(*column_names)
|
|
163
|
+
pluck(*column_names).first
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def to_ary
|
|
167
|
+
records.dup
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def method_missing(method_name, *args)
|
|
171
|
+
return super unless klass.scopes&.key?(method_name)
|
|
172
|
+
|
|
173
|
+
instance_exec(*args, &klass.scopes[method_name])
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def respond_to_missing?(method_name, include_private = false)
|
|
177
|
+
klass.scopes&.key?(method_name) || super
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
private
|
|
181
|
+
|
|
182
|
+
attr_writer :conditions, :order_values, :klass, :all_records
|
|
183
|
+
|
|
184
|
+
def apply_conditions(records, conditions)
|
|
185
|
+
return records if conditions.blank?
|
|
186
|
+
|
|
187
|
+
records.select do |record|
|
|
188
|
+
conditions.matches?(record)
|
|
114
189
|
end
|
|
115
190
|
end
|
|
116
191
|
|
|
117
|
-
def
|
|
118
|
-
|
|
192
|
+
def check_if_method_has_arguments!(method_name, args)
|
|
193
|
+
return unless args.blank?
|
|
194
|
+
|
|
195
|
+
raise ArgumentError,
|
|
196
|
+
"The method .#{method_name}() must contain arguments."
|
|
119
197
|
end
|
|
120
|
-
|
|
121
|
-
def range_to_array(range)
|
|
122
|
-
return range.to_a unless range.end.nil?
|
|
123
198
|
|
|
124
|
-
|
|
125
|
-
(
|
|
199
|
+
def preprocess_order_args(order_args)
|
|
200
|
+
order_args.reject!(&:blank?)
|
|
201
|
+
return order_args.reverse! unless order_args.first.is_a?(String)
|
|
202
|
+
|
|
203
|
+
ary = order_args.first.split(', ')
|
|
204
|
+
ary.map! { |e| e.split(/\W+/) }.reverse!
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def apply_order_values(records, args)
|
|
208
|
+
ordered_records = records.dup
|
|
209
|
+
|
|
210
|
+
args.each do |arg|
|
|
211
|
+
field, dir = if arg.is_a?(Hash)
|
|
212
|
+
arg.to_a.flatten.map(&:to_sym)
|
|
213
|
+
elsif arg.is_a?(Array)
|
|
214
|
+
arg.map(&:to_sym)
|
|
215
|
+
else
|
|
216
|
+
arg.to_sym
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
ordered_records.sort! do |a, b|
|
|
220
|
+
if dir.present? && dir.to_sym.upcase.equal?(:DESC)
|
|
221
|
+
b[field] <=> a[field]
|
|
222
|
+
else
|
|
223
|
+
a[field] <=> b[field]
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
ordered_records
|
|
126
229
|
end
|
|
127
230
|
end
|
|
128
231
|
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
|