active_hash 1.4.0 → 1.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +4 -0
- data/README.md +380 -380
- data/lib/active_hash/base.rb +29 -5
- data/lib/active_hash/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 652802c90d3e70506b8997f124021284e8b073be
|
4
|
+
data.tar.gz: a4b876f9bc3c7316c6d12f3945e2b74b20b8a11f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 53e0ad1f1e45a7adb6cd51ea367102ec959a21c19245d52ec9534c6976754fdf888efe3da463818ff1c14c9c0048fa2c0e51a9b4164857ee811076eb6af11612
|
7
|
+
data.tar.gz: cb66a911b00f3b9b4c25de6485fc0e7b9fff3b66efeabd5e70a5dcf52134afba7d990951cc232beaec45dc4ed12b1760c3fe79e1a818b7d317bd8f6a15692d67
|
data/CHANGELOG
CHANGED
data/README.md
CHANGED
@@ -18,38 +18,38 @@ ActiveHash also ships with:
|
|
18
18
|
## Installation
|
19
19
|
|
20
20
|
Bundler:
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
```ruby
|
22
|
+
gem 'active_hash'
|
23
|
+
```
|
24
24
|
Other:
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
```ruby
|
26
|
+
gem install active_hash
|
27
|
+
```
|
28
28
|
## Reason for being
|
29
29
|
|
30
30
|
We wrote ActiveHash so that we could use simple, in-memory, ActiveRecord-like data structures that play well with Rails forms, like:
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
31
|
+
```ruby
|
32
|
+
# in app/models/country.rb
|
33
|
+
class Country < ActiveHash::Base
|
34
|
+
self.data = [
|
35
|
+
{:id => 1, :name => "US"},
|
36
|
+
{:id => 2, :name => "Canada"}
|
37
|
+
]
|
38
|
+
end
|
39
|
+
|
40
|
+
# in some view
|
41
|
+
<%= collection_select :person, :country_id, Country.all, :id, :name %>
|
42
|
+
```
|
43
43
|
Before ActiveHash, we did things like:
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
44
|
+
```ruby
|
45
|
+
# in app/models/person.rb
|
46
|
+
class Person < ActiveRecord::Base
|
47
|
+
COUNTRIES = ["US", "Canada"]
|
48
|
+
end
|
49
|
+
|
50
|
+
# in some view
|
51
|
+
<%= collection_select :person, :country_id, Person::COUNTRIES, :to_s, :to_s %>
|
52
|
+
```
|
53
53
|
The majority of ActiveHash uses involve setting up some data at boot time, and never modifying that data at runtime.
|
54
54
|
|
55
55
|
## Usage
|
@@ -61,261 +61,261 @@ To use ActiveHash, you need to:
|
|
61
61
|
* Define your fields and/or default values
|
62
62
|
|
63
63
|
A quick example would be:
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
64
|
+
```ruby
|
65
|
+
class Country < ActiveHash::Base
|
66
|
+
self.data = [
|
67
|
+
{:id => 1, :name => "US"},
|
68
|
+
{:id => 2, :name => "Canada"}
|
69
|
+
]
|
70
|
+
end
|
71
|
+
|
72
|
+
country = Country.new(:name => "Mexico")
|
73
|
+
country.name # => "Mexico"
|
74
|
+
country.name? # => true
|
75
|
+
```
|
76
76
|
You can also use _create_:
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
77
|
+
```ruby
|
78
|
+
class Country < ActiveHash::Base
|
79
|
+
field :name
|
80
|
+
create :id => 1, :name => "US"
|
81
|
+
create :id => 2, :name => "Canada"
|
82
|
+
end
|
83
|
+
```
|
84
84
|
You can also use _add_:
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
85
|
+
```ruby
|
86
|
+
class Country < ActiveHash::Base
|
87
|
+
field :name
|
88
|
+
add :id => 1, :name => "US"
|
89
|
+
add :id => 2, :name => "Canada"
|
90
|
+
end
|
91
|
+
```
|
92
92
|
## Auto-Defined fields
|
93
93
|
|
94
94
|
ActiveHash will auto-define all fields for you when you load the hash. For example, if you have the following class:
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
95
|
+
```ruby
|
96
|
+
class CustomField < ActiveHash::Base
|
97
|
+
self.data = [
|
98
|
+
{:custom_field_1 => "foo"},
|
99
|
+
{:custom_field_2 => "foo"},
|
100
|
+
{:custom_field_3 => "foo"}
|
101
|
+
]
|
102
|
+
end
|
103
|
+
```
|
104
104
|
Once you call CustomField.all it will define methods for :custom_field_1, :custom_field_2 etc...
|
105
105
|
|
106
106
|
If you need the fields at load time, as opposed to after .all is called, you can also define them manually, like so:
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
107
|
+
```ruby
|
108
|
+
class CustomField < ActiveHash::Base
|
109
|
+
fields :custom_field_1, :custom_field_2, :custom_field_3
|
110
|
+
end
|
111
|
+
```
|
112
112
|
NOTE: auto-defined fields will _not_ override fields you've defined, either on the class or on the instance.
|
113
113
|
|
114
114
|
## Defining Fields with default values
|
115
115
|
|
116
116
|
If some of your hash values contain nil, and you want to provide a default, you can specify defaults with the :field method:
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
117
|
+
```ruby
|
118
|
+
class Country < ActiveHash::Base
|
119
|
+
field :is_axis_of_evil, :default => false
|
120
|
+
end
|
121
|
+
```
|
122
122
|
## Defining Data
|
123
123
|
|
124
124
|
You can define data inside your class or outside. For example, you might have a class like this:
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
125
|
+
```ruby
|
126
|
+
# app/models/country.rb
|
127
|
+
class Country < ActiveHash::Base
|
128
|
+
end
|
129
|
+
|
130
|
+
# config/initializers/data.rb
|
131
|
+
Rails.application.config.to_prepare do
|
132
|
+
Country.data = [
|
133
|
+
{:id => 1, :name => "US"},
|
134
|
+
{:id => 2, :name => "Canada"}
|
135
|
+
]
|
136
|
+
end
|
137
|
+
```
|
138
138
|
If you prefer to store your data in YAML, see below.
|
139
139
|
|
140
140
|
## Class Methods
|
141
141
|
|
142
142
|
ActiveHash gives you ActiveRecord-esque methods like:
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
143
|
+
```ruby
|
144
|
+
Country.all # => returns all Country objects
|
145
|
+
Country.count # => returns the length of the .data array
|
146
|
+
Country.first # => returns the first country object
|
147
|
+
Country.last # => returns the last country object
|
148
|
+
Country.find 1 # => returns the first country object with that id
|
149
|
+
Country.find [1,2] # => returns all Country objects with ids in the array
|
150
|
+
Country.find :all # => same as .all
|
151
|
+
Country.find :all, args # => the second argument is totally ignored, but allows it to play nicely with AR
|
152
|
+
Country.find_by_id 1 # => find the first object that matches the id
|
153
|
+
```
|
154
154
|
It also gives you a few dynamic finder methods. For example, if you defined :name as a field, you'd get:
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
155
|
+
```ruby
|
156
|
+
Country.find_by_name "foo" # => returns the first object matching that name
|
157
|
+
Country.find_all_by_name "foo" # => returns an array of the objects with matching names
|
158
|
+
Country.find_by_id_and_name 1, "Germany" # => returns the first object matching that id and name
|
159
|
+
Country.find_all_by_id_and_name 1, "Germany" # => returns an array of objects matching that name and id
|
160
|
+
```
|
161
161
|
## Instance Methods
|
162
162
|
|
163
163
|
ActiveHash objects implement enough of the ActiveRecord api to satisfy most common needs. For example:
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
164
|
+
```
|
165
|
+
Country#id # => returns the id or nil
|
166
|
+
Country#id= # => sets the id attribute
|
167
|
+
Country#quoted_id # => returns the numeric id
|
168
|
+
Country#to_param # => returns the id as a string
|
169
|
+
Country#new_record? # => returns true if is not part of Country.all, false otherwise
|
170
|
+
Country#readonly? # => true
|
171
|
+
Country#hash # => the hash of the id (or the hash of nil)
|
172
|
+
Country#eql? # => compares type and id, returns false if id is nil
|
173
|
+
```
|
174
174
|
ActiveHash also gives you methods related to the fields you defined. For example, if you defined :name as a field, you'd get:
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
175
|
+
```
|
176
|
+
Country#name # => returns the passed in name
|
177
|
+
Country#name? # => returns true if the name is not blank
|
178
|
+
Country#name= # => sets the name
|
179
|
+
```
|
180
180
|
## Saving in-memory records
|
181
181
|
|
182
182
|
The ActiveHash::Base.all method functions like an in-memory data store. You can save your records to the the .all array by using standard ActiveRecord create and save methods:
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
183
|
+
```ruby
|
184
|
+
Country.all # => []
|
185
|
+
Country.create
|
186
|
+
Country.all # [ <Country :id => 1> ]
|
187
|
+
country = Country.new
|
188
|
+
country.new_record? # => true
|
189
|
+
country.save
|
190
|
+
country.new_record? # => false
|
191
|
+
Country.all # [ <Country :id => 1>, <Country :id => 2> ]
|
192
|
+
```
|
193
193
|
Notice that when adding records to the collection, it will auto-increment the id for you by default. If you use string ids, it will not auto-increment the id. Available methods are:
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
194
|
+
```
|
195
|
+
Country.insert( record )
|
196
|
+
Country#save
|
197
|
+
Country#save!
|
198
|
+
Country.create
|
199
|
+
Country.create!
|
200
|
+
```
|
201
201
|
As such, ActiveHash::Base and its descendants should work with Fixjour or FactoryGirl, so you can treat ActiveHash records the same way you would any other ActiveRecord model in tests.
|
202
202
|
|
203
203
|
To clear all records from the in-memory array, call delete_all:
|
204
|
-
|
205
|
-
|
206
|
-
|
204
|
+
```ruby
|
205
|
+
Country.delete_all # => does not affect the yaml files in any way - just clears the in-memory array which can be useful for testing
|
206
|
+
```
|
207
207
|
## Referencing ActiveHash objects from ActiveRecord Associations
|
208
208
|
|
209
209
|
One common use case for ActiveHash is to have top-level objects in memory that ActiveRecord objects belong to.
|
210
210
|
|
211
211
|
In versions of ActiveRecord previous to 3.1, you should be able to do the following:
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
212
|
+
```ruby
|
213
|
+
class Country < ActiveHash::Base
|
214
|
+
end
|
215
|
+
|
216
|
+
class Person < ActiveRecord::Base
|
217
|
+
belongs_to :country
|
218
|
+
end
|
219
|
+
```
|
220
220
|
However, as of ActiveRecord 3.1 support for ActiveRecord's `belong_to` is broken. Instead, you must extend ActiveHash::Associations::ActiveRecordExtensions method:
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
221
|
+
```ruby
|
222
|
+
class Country < ActiveHash::Base
|
223
|
+
end
|
224
|
+
|
225
|
+
class Person < ActiveRecord::Base
|
226
|
+
extend ActiveHash::Associations::ActiveRecordExtensions
|
227
|
+
belongs_to :country
|
228
|
+
end
|
229
|
+
```
|
230
230
|
NOTE: this needs to be called on a subclass of ActiveRecord::Base. If you extend ActiveRecord::Base, it will not work.
|
231
231
|
If you want to extend ActiveRecord::Base so all your AR models can belong to ActiveHash::Base objects, you can use the
|
232
232
|
`belongs_to_active_hash` method:
|
233
|
+
```ruby
|
234
|
+
ActiveRecord::Base.extend ActiveHash::Associations::ActiveRecordExtensions
|
233
235
|
|
234
|
-
|
235
|
-
|
236
|
-
class Country < ActiveHash::Base
|
237
|
-
end
|
238
|
-
|
239
|
-
class Person < ActiveRecord::Base
|
240
|
-
belongs_to_active_hash :country
|
241
|
-
end
|
236
|
+
class Country < ActiveHash::Base
|
237
|
+
end
|
242
238
|
|
239
|
+
class Person < ActiveRecord::Base
|
240
|
+
belongs_to_active_hash :country
|
241
|
+
end
|
242
|
+
```
|
243
243
|
With ActiveRecord versions < 3.1, ActiveHash will also work as a polymorphic parent:
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
244
|
+
```ruby
|
245
|
+
class Country < ActiveHash::Base
|
246
|
+
end
|
247
|
+
|
248
|
+
class Person < ActiveRecord::Base
|
249
|
+
belongs_to :location, :polymorphic => true
|
250
|
+
end
|
251
|
+
|
252
|
+
person = Person.new
|
253
|
+
person.location = Country.first
|
254
|
+
person.save
|
255
|
+
person.location # => Country.first
|
256
|
+
```
|
257
257
|
However, as of ActiveRecord 3.1 this will not work. If you need support for that, please open an issue.
|
258
258
|
|
259
259
|
### Using shortcuts
|
260
260
|
|
261
261
|
Since ActiveHashes usually are static, we can use shortcuts to assign via an easy to remember string instead of an obscure ID number.
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
262
|
+
```ruby
|
263
|
+
# app/models/country.rb
|
264
|
+
class Country < ActiveHash::Base
|
265
|
+
end
|
266
|
+
|
267
|
+
# app/models/person.rb
|
268
|
+
class Person < ActiveRecord::Base
|
269
|
+
extend ActiveHash::Associations::ActiveRecordExtensions
|
270
|
+
belongs_to_active_hash :country, :shortcuts => [:name]
|
271
|
+
end
|
272
|
+
|
273
|
+
# config/initializers/data.rb
|
274
|
+
Rails.application.config.to_prepare do
|
275
|
+
Country.data = [
|
276
|
+
{:id => 1, :name => "US"},
|
277
|
+
{:id => 2, :name => "Canada"}
|
278
|
+
]
|
279
|
+
end
|
280
|
+
|
281
|
+
# Using `rails console`
|
282
|
+
john = Person.new
|
283
|
+
john.country_name = "US"
|
284
|
+
# Is the same as doing `john.country = Country.find_by_name("US")`
|
285
|
+
john.country_name
|
286
|
+
# Will return "US", and is the same as doing `john.country.try(:name)`
|
287
|
+
```
|
288
288
|
You can have multiple shortcuts, so settings `:shortcuts => [:name, :friendly_name]` will enable you to use `#country_name=` and `#country_friendly_name=`.
|
289
289
|
|
290
290
|
## Referencing ActiveRecord objects from ActiveHash
|
291
291
|
|
292
292
|
If you include the ActiveHash::Associations module, you can also create associations from your ActiveHash classes, like so:
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
293
|
+
```ruby
|
294
|
+
class Country < ActiveHash::Base
|
295
|
+
include ActiveHash::Associations
|
296
|
+
has_many :people
|
297
|
+
end
|
298
|
+
|
299
|
+
class Person < ActiveHash::Base
|
300
|
+
include ActiveHash::Associations
|
301
|
+
belongs_to :country
|
302
|
+
has_many :pets
|
303
|
+
end
|
304
|
+
|
305
|
+
class Pet < ActiveRecord::Base
|
306
|
+
end
|
307
|
+
```
|
308
308
|
Once you define a belongs to, you also get the setter method:
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
309
|
+
```ruby
|
310
|
+
class City < ActiveHash::Base
|
311
|
+
include ActiveHash::Associations
|
312
|
+
belongs_to :state
|
313
|
+
end
|
314
|
+
|
315
|
+
city = City.new
|
316
|
+
city.state = State.first
|
317
|
+
city.state_id # is State.first.id
|
318
|
+
```
|
319
319
|
NOTE: You cannot use ActiveHash objects as children of ActiveRecord and I don't plan on adding support for that. It doesn't really make any sense, since you'd have to hard-code your database ids in your class or yaml files, which is a dependency inversion.
|
320
320
|
|
321
321
|
Thanks to baldwindavid for the ideas and code on that one.
|
@@ -323,138 +323,138 @@ Thanks to baldwindavid for the ideas and code on that one.
|
|
323
323
|
## ActiveYaml
|
324
324
|
|
325
325
|
If you want to store your data in YAML files, just inherit from ActiveYaml and specify your path information:
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
326
|
+
```ruby
|
327
|
+
class Country < ActiveYaml::Base
|
328
|
+
end
|
329
|
+
```
|
330
330
|
By default, this class will look for a yml file named "countries.yml" in the same directory as the file. You can either change the directory it looks in, the filename it looks for, or both:
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
331
|
+
```ruby
|
332
|
+
class Country < ActiveYaml::Base
|
333
|
+
set_root_path "/u/data"
|
334
|
+
set_filename "sample"
|
335
|
+
end
|
336
|
+
```
|
337
337
|
The above example will look for the file "/u/data/sample.yml".
|
338
338
|
|
339
339
|
Since ActiveYaml just creates a hash from the YAML file, you will have all fields specified in YAML auto-defined for you. You can format your YAML as an array, or as a hash:
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
340
|
+
```
|
341
|
+
# array style
|
342
|
+
- id: 1
|
343
|
+
name: US
|
344
|
+
- id: 2
|
345
|
+
name: Canada
|
346
|
+
- id: 3
|
347
|
+
name: Mexico
|
348
|
+
|
349
|
+
# hash style
|
350
|
+
us:
|
351
|
+
id: 1
|
352
|
+
name: US
|
353
|
+
canada:
|
354
|
+
id: 2
|
355
|
+
name: Canada
|
356
|
+
mexico:
|
357
|
+
id: 3
|
358
|
+
name: Mexico
|
359
|
+
```
|
360
360
|
### Multiple files per model
|
361
361
|
|
362
362
|
You can use multiple files to store your data. You will have to choose between hash or array style as you cannot use both for one model.
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
363
|
+
```ruby
|
364
|
+
class Country < ActiveYaml::Base
|
365
|
+
use_mutliple_files
|
366
|
+
set_filenames "europe", "america", "asia", "africa"
|
367
|
+
end
|
368
|
+
```
|
369
369
|
### Using aliases in YAML
|
370
370
|
|
371
371
|
Aliases can be used in ActiveYaml using either array or hash style by including `ActiveYaml::Aliases`.
|
372
372
|
With that module included, keys beginning with a '/' character can be safely added, and will be ignored, allowing you to add aliases anywhere in your code:
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
373
|
+
```
|
374
|
+
# Array Style
|
375
|
+
- /aliases:
|
376
|
+
soda_flavor: &soda_flavor
|
377
|
+
sweet
|
378
|
+
soda_price: &soda_price
|
379
|
+
1.0
|
380
|
+
|
381
|
+
- id: 1
|
382
|
+
name: Coke
|
383
|
+
flavor: *soda_flavor
|
384
|
+
price: *soda_price
|
385
|
+
|
386
|
+
|
387
|
+
# Key style
|
388
|
+
/aliases:
|
389
|
+
soda_flavor: &soda_flavor
|
390
|
+
sweet
|
391
|
+
soda_price: &soda_price
|
392
|
+
1.0
|
393
|
+
|
394
|
+
coke:
|
395
|
+
id: 1
|
396
|
+
name: Coke
|
397
|
+
flavor: *soda_flavor
|
398
|
+
price: *soda_price
|
399
|
+
|
400
|
+
class Soda < ActiveYaml::Base
|
401
|
+
include ActiveYaml::Aliases
|
402
|
+
end
|
403
|
+
|
404
|
+
Soda.length # => 1
|
405
|
+
Soda.first.flavor # => sweet
|
406
|
+
Soda.first.price # => 1.0
|
407
|
+
```
|
408
408
|
## ActiveJSON
|
409
409
|
|
410
410
|
If you want to store your data in JSON files, just inherit from ActiveJSON and specify your path information:
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
411
|
+
```ruby
|
412
|
+
class Country < ActiveJSON::Base
|
413
|
+
end
|
414
|
+
```
|
415
415
|
By default, this class will look for a json file named "countries.json" in the same directory as the file. You can either change the directory it looks in, the filename it looks for, or both:
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
416
|
+
```ruby
|
417
|
+
class Country < ActiveJSON::Base
|
418
|
+
set_root_path "/u/data"
|
419
|
+
set_filename "sample"
|
420
|
+
end
|
421
|
+
```
|
422
422
|
The above example will look for the file "/u/data/sample.json".
|
423
423
|
|
424
424
|
Since ActiveJSON just creates a hash from the JSON file, you will have all fields specified in JSON auto-defined for you. You can format your JSON as an array, or as a hash:
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
}
|
448
|
-
},
|
449
|
-
{ "canada":
|
450
|
-
{
|
451
|
-
"id": 2,
|
452
|
-
"name": "Canada",
|
453
|
-
"custom_field_2": "value2"
|
454
|
-
}
|
455
|
-
}
|
425
|
+
```ruby
|
426
|
+
# array style
|
427
|
+
[
|
428
|
+
{
|
429
|
+
"id": 1,
|
430
|
+
"name": "US",
|
431
|
+
"custom_field_1": "value1"
|
432
|
+
},
|
433
|
+
{
|
434
|
+
"id": 2,
|
435
|
+
"name": "Canada",
|
436
|
+
"custom_field_2": "value2"
|
437
|
+
}
|
438
|
+
]
|
439
|
+
|
440
|
+
# hash style
|
441
|
+
{
|
442
|
+
{ "us":
|
443
|
+
{
|
444
|
+
"id": 1,
|
445
|
+
"name": "US",
|
446
|
+
"custom_field_1": "value1"
|
456
447
|
}
|
457
|
-
|
448
|
+
},
|
449
|
+
{ "canada":
|
450
|
+
{
|
451
|
+
"id": 2,
|
452
|
+
"name": "Canada",
|
453
|
+
"custom_field_2": "value2"
|
454
|
+
}
|
455
|
+
}
|
456
|
+
}
|
457
|
+
```
|
458
458
|
### Multiple files per model
|
459
459
|
|
460
460
|
This works as it does for `ActiveYaml`
|
@@ -462,29 +462,29 @@ Since ActiveJSON just creates a hash from the JSON file, you will have all field
|
|
462
462
|
## ActiveFile
|
463
463
|
|
464
464
|
If you store encrypted data, or you'd like to store your flat files as CSV or XML or any other format, you can easily include ActiveHash to parse and load your file. Just add a custom ::load_file method, and define the extension you want the file to use:
|
465
|
+
```ruby
|
466
|
+
class Country < ActiveFile::Base
|
467
|
+
set_root_path "/u/data"
|
468
|
+
set_filename "sample"
|
465
469
|
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
class << self
|
471
|
-
def extension
|
472
|
-
".super_secret"
|
473
|
-
end
|
474
|
-
|
475
|
-
def load_file
|
476
|
-
MyAwesomeDecoder.load_file(full_path)
|
477
|
-
end
|
478
|
-
end
|
470
|
+
class << self
|
471
|
+
def extension
|
472
|
+
".super_secret"
|
479
473
|
end
|
480
474
|
|
475
|
+
def load_file
|
476
|
+
MyAwesomeDecoder.load_file(full_path)
|
477
|
+
end
|
478
|
+
end
|
479
|
+
end
|
480
|
+
```
|
481
481
|
The two methods you need to implement are load_file, which needs to return an array of hashes, and .extension, which returns the file extension you are using. You have full_path available to you if you wish, or you can provide your own path.
|
482
482
|
|
483
483
|
Setting the default file location in Rails:
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
484
|
+
```ruby
|
485
|
+
# config/initializers/active_file.rb
|
486
|
+
ActiveFile::Base.set_root_path "config/activefiles"
|
487
|
+
```
|
488
488
|
In Rails, in development mode, it reloads the entire class, which reloads the file. In production, the data cached in memory.
|
489
489
|
|
490
490
|
NOTE: By default, .full_path refers to the current working directory. In a rails app, this will be RAILS_ROOT.
|
@@ -494,17 +494,17 @@ NOTE: By default, .full_path refers to the current working directory. In a rai
|
|
494
494
|
ActiveHash can expose its data in an Enumeration by setting constants for each record. This allows records to be accessed in code through a constant set in the ActiveHash class.
|
495
495
|
|
496
496
|
The field to be used as the constant is set using _enum_accessor_ which takes the name of a field as an argument.
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
497
|
+
```ruby
|
498
|
+
class Country < ActiveHash::Base
|
499
|
+
include ActiveHash::Enum
|
500
|
+
self.data = [
|
501
|
+
{:id => 1, :name => "US", :capital => "Washington, DC"},
|
502
|
+
{:id => 2, :name => "Canada", :capital => "Ottawa"},
|
503
|
+
{:id => 3, :name => "Mexico", :capital => "Mexico City"}
|
504
|
+
]
|
505
|
+
enum_accessor :name
|
506
|
+
end
|
507
|
+
```
|
508
508
|
Records can be accessed by looking up the field constant:
|
509
509
|
|
510
510
|
>> Country::US.capital
|
@@ -515,19 +515,19 @@ Records can be accessed by looking up the field constant:
|
|
515
515
|
=> #<Country:0x10229fb28 @attributes={:name=>"Canada", :id=>2}
|
516
516
|
|
517
517
|
You may also use multiple attributes to generate the constant, like so:
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
518
|
+
```ruby
|
519
|
+
class Town < ActiveHash::Base
|
520
|
+
include ActiveHash::Enum
|
521
|
+
self.data = [
|
522
|
+
{:id => 1, :name => "Columbus", :state => "NY"},
|
523
|
+
{:id => 2, :name => "Columbus", :state => "OH"}
|
524
|
+
]
|
525
|
+
enum_accessor :name, :state
|
526
|
+
end
|
527
|
+
|
528
|
+
>> Town::COLUMBUS_NY
|
529
|
+
>> Town::COLUMBUS_OH
|
530
|
+
```
|
531
531
|
Constants are formed by first stripping all non-word characters and then upcasing the result. This means strings like "Blazing Saddles", "ReBar", "Mike & Ike" and "Ho! Ho! Ho!" become BLAZING_SADDLES, REBAR, MIKE_IKE and HO_HO_HO.
|
532
532
|
|
533
533
|
The field specified as the _enum_accessor_ must contain unique data values.
|
data/lib/active_hash/base.rb
CHANGED
@@ -15,9 +15,9 @@ module ActiveHash
|
|
15
15
|
class Base
|
16
16
|
|
17
17
|
if respond_to?(:class_attribute)
|
18
|
-
class_attribute :_data, :dirty
|
18
|
+
class_attribute :_data, :dirty, :default_attributes
|
19
19
|
else
|
20
|
-
class_inheritable_accessor :_data, :dirty
|
20
|
+
class_inheritable_accessor :_data, :dirty, :default_attributes
|
21
21
|
end
|
22
22
|
|
23
23
|
if Object.const_defined?(:ActiveModel)
|
@@ -35,7 +35,7 @@ module ActiveHash
|
|
35
35
|
if Object.const_defined?(:ActiveModel)
|
36
36
|
model_name.cache_key
|
37
37
|
else
|
38
|
-
ActiveSupport::Inflector.tableize(self)
|
38
|
+
ActiveSupport::Inflector.tableize(self).downcase
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -61,6 +61,10 @@ module ActiveHash
|
|
61
61
|
true
|
62
62
|
end
|
63
63
|
|
64
|
+
def empty?
|
65
|
+
false
|
66
|
+
end
|
67
|
+
|
64
68
|
def data
|
65
69
|
_data
|
66
70
|
end
|
@@ -157,6 +161,10 @@ module ActiveHash
|
|
157
161
|
end
|
158
162
|
end
|
159
163
|
|
164
|
+
def find_by(options)
|
165
|
+
where(options).first
|
166
|
+
end
|
167
|
+
|
160
168
|
def count
|
161
169
|
all.length
|
162
170
|
end
|
@@ -210,6 +218,7 @@ module ActiveHash
|
|
210
218
|
validate_field(field_name)
|
211
219
|
field_names << field_name
|
212
220
|
|
221
|
+
add_default_value(field_name, options[:default]) if options[:default]
|
213
222
|
define_getter_method(field_name, options[:default])
|
214
223
|
define_setter_method(field_name)
|
215
224
|
define_interrogator_method(field_name)
|
@@ -266,6 +275,11 @@ module ActiveHash
|
|
266
275
|
|
267
276
|
private :configuration_for_custom_finder
|
268
277
|
|
278
|
+
def add_default_value field_name, default_value
|
279
|
+
self.default_attributes ||= {}
|
280
|
+
self.default_attributes[field_name] = default_value
|
281
|
+
end
|
282
|
+
|
269
283
|
def define_getter_method(field, default_value)
|
270
284
|
unless has_instance_method?(field)
|
271
285
|
define_method(field) do
|
@@ -385,8 +399,6 @@ module ActiveHash
|
|
385
399
|
|
386
400
|
end
|
387
401
|
|
388
|
-
attr_reader :attributes
|
389
|
-
|
390
402
|
def initialize(attributes = {})
|
391
403
|
attributes.symbolize_keys!
|
392
404
|
@attributes = attributes
|
@@ -395,10 +407,22 @@ module ActiveHash
|
|
395
407
|
end
|
396
408
|
end
|
397
409
|
|
410
|
+
def attributes
|
411
|
+
if self.class.default_attributes
|
412
|
+
self.class.default_attributes.merge @attributes
|
413
|
+
else
|
414
|
+
@attributes
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
398
418
|
def [](key)
|
399
419
|
attributes[key]
|
400
420
|
end
|
401
421
|
|
422
|
+
def _read_attribute(key)
|
423
|
+
attributes[key]
|
424
|
+
end
|
425
|
+
|
402
426
|
def []=(key, val)
|
403
427
|
attributes[key] = val
|
404
428
|
end
|
data/lib/active_hash/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_hash
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.
|
4
|
+
version: 1.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeff Dean
|
@@ -28,7 +28,7 @@ authors:
|
|
28
28
|
autorequire:
|
29
29
|
bindir: bin
|
30
30
|
cert_chain: []
|
31
|
-
date:
|
31
|
+
date: 2015-09-13 00:00:00.000000000 Z
|
32
32
|
dependencies:
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: activesupport
|
@@ -86,7 +86,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
86
86
|
version: '0'
|
87
87
|
requirements: []
|
88
88
|
rubyforge_project:
|
89
|
-
rubygems_version: 2.
|
89
|
+
rubygems_version: 2.4.8
|
90
90
|
signing_key:
|
91
91
|
specification_version: 4
|
92
92
|
summary: An ActiveRecord-like model that uses a hash or file as a datasource
|