zilkey-active_hash 0.1.0 → 0.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.
- data/CHANGELOG +5 -0
- data/README.md +30 -10
- data/VERSION +1 -1
- data/active_hash.gemspec +58 -0
- data/lib/active_file/base.rb +1 -5
- data/lib/active_hash/base.rb +41 -15
- data/lib/active_yaml/base.rb +1 -0
- data/spec/active_file/base_spec.rb +10 -0
- data/spec/active_hash/base_spec.rb +56 -1
- data/spec/active_yaml/base_spec.rb +1 -0
- data/spec/active_yaml/sample.yml +9 -0
- metadata +4 -2
data/CHANGELOG
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
2009-07-23
|
|
2
|
+
- Added support for auto-defining methods based on hash keys in ActiveHash::Base
|
|
3
|
+
- Changed the :field and :fields API so that they don't overwrite existing methods (useful when ActiveHash auto-defines methods)
|
|
4
|
+
- Fixed a bug where ActiveFile incorrectly set the root_path to be the path in the gem directory, not the current working directory
|
|
5
|
+
|
data/README.md
CHANGED
|
@@ -22,8 +22,8 @@ ActiveHash also ships with:
|
|
|
22
22
|
To use ActiveHash, you need to:
|
|
23
23
|
|
|
24
24
|
* Inherit from ActiveHash::Base
|
|
25
|
-
* Define your fields
|
|
26
25
|
* Define your data
|
|
26
|
+
* (optionally) Define your fields and/or default values
|
|
27
27
|
|
|
28
28
|
A quick example would be:
|
|
29
29
|
|
|
@@ -35,12 +35,33 @@ A quick example would be:
|
|
|
35
35
|
]
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
##
|
|
38
|
+
## Auto-Defined fields
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
ActiveHash will auto-define all fields for you when you load the hash. For example, if you have the following class:
|
|
41
|
+
|
|
42
|
+
class CustomField < ActiveYaml::Base
|
|
43
|
+
self.data = [
|
|
44
|
+
{:custom_field_1 => "foo"},
|
|
45
|
+
{:custom_field_2 => "foo"},
|
|
46
|
+
{:custom_field_3 => "foo"}
|
|
47
|
+
]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
Once you call CustomField.all it will define methods for :custom_field_1, :custom_field_2 etc...
|
|
51
|
+
|
|
52
|
+
If you need the fields at load time, as opposed to after .all is called, you can also define them manually, like so:
|
|
53
|
+
|
|
54
|
+
class CustomField < ActiveYaml::Base
|
|
55
|
+
fields :custom_field_1, :custom_field_2, :custom_field_3
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
NOTE: auto-defined fields will _not_ override fields you've defined, either on the class or on the instance.
|
|
59
|
+
|
|
60
|
+
## Defining Fields with default values
|
|
61
|
+
|
|
62
|
+
If some of your hash values contain nil, and you want to provide a default, you can specify defaults with the :field method:
|
|
41
63
|
|
|
42
64
|
class Country < ActiveHash::Base
|
|
43
|
-
fields :name, :population
|
|
44
65
|
field :is_axis_of_evil, :default => false
|
|
45
66
|
end
|
|
46
67
|
|
|
@@ -50,7 +71,6 @@ You can define data inside your class or outside. For example, you might have a
|
|
|
50
71
|
|
|
51
72
|
# app/models/country.rb
|
|
52
73
|
class Country < ActiveHash::Base
|
|
53
|
-
fields :name, :population
|
|
54
74
|
end
|
|
55
75
|
|
|
56
76
|
# config/initializers/data.rb
|
|
@@ -102,7 +122,6 @@ ActiveHash also gives you methods related to the fields you defined. For exampl
|
|
|
102
122
|
You can create .belongs_to associations from rails objects, like so:
|
|
103
123
|
|
|
104
124
|
class Country < ActiveHash::Base
|
|
105
|
-
fields :name, :population
|
|
106
125
|
end
|
|
107
126
|
|
|
108
127
|
class Person < ActiveRecord::Base
|
|
@@ -118,7 +137,6 @@ You can also use standard rails view helpers, like #collection_select:
|
|
|
118
137
|
If you want to store your data in YAML files, just inherit from ActiveYaml and specify your path information:
|
|
119
138
|
|
|
120
139
|
class Country < ActiveYaml::Base
|
|
121
|
-
field :name
|
|
122
140
|
end
|
|
123
141
|
|
|
124
142
|
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:
|
|
@@ -126,13 +144,14 @@ By default, this class will look for a yml file named "countries.yml" in the sam
|
|
|
126
144
|
class Country < ActiveYaml::Base
|
|
127
145
|
set_root_path "/u/data"
|
|
128
146
|
set_filename "sample"
|
|
129
|
-
field :name
|
|
130
147
|
end
|
|
131
148
|
|
|
132
149
|
The above example will look for the file "/u/data/sample.yml".
|
|
133
150
|
|
|
134
151
|
ActiveYaml, as well as ActiveFile, check the mtime of the file you specified, and reloads the data if the mtime has changed. So you can replace the data in the files even if your app is running in production mode in rails.
|
|
135
152
|
|
|
153
|
+
Since ActiveYaml just creates a hash from the YAML file, you will have all fields specified in YAML auto-defined for you once you call all.
|
|
154
|
+
|
|
136
155
|
## ActiveFile
|
|
137
156
|
|
|
138
157
|
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 extend ActiveHash to parse and load your file. Just add a custom ::load_file method, and define the extension you want the file to use:
|
|
@@ -140,7 +159,6 @@ If you store encrypted data, or you'd like to store your flat files as CSV or XM
|
|
|
140
159
|
class Country < ActiveFile::Base
|
|
141
160
|
set_root_path "/u/data"
|
|
142
161
|
set_filename "sample"
|
|
143
|
-
field :name
|
|
144
162
|
|
|
145
163
|
class << self
|
|
146
164
|
def extension
|
|
@@ -153,7 +171,9 @@ If you store encrypted data, or you'd like to store your flat files as CSV or XM
|
|
|
153
171
|
end
|
|
154
172
|
end
|
|
155
173
|
|
|
156
|
-
The two methods you need to implement are load_file, which needs to return
|
|
174
|
+
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.
|
|
175
|
+
|
|
176
|
+
NOTE: By default, .full_path refers to the current working directory. In a rails app, this will be RAILS_ROOT.
|
|
157
177
|
|
|
158
178
|
## Authors
|
|
159
179
|
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.2.0
|
data/active_hash.gemspec
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |s|
|
|
4
|
+
s.name = %q{active_hash}
|
|
5
|
+
s.version = "0.2.0"
|
|
6
|
+
|
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
8
|
+
s.authors = ["Jeff Dean", "Mike Dalessio"]
|
|
9
|
+
s.date = %q{2009-07-23}
|
|
10
|
+
s.email = %q{jeff@zilkey.com}
|
|
11
|
+
s.extra_rdoc_files = [
|
|
12
|
+
"LICENSE",
|
|
13
|
+
"README.md"
|
|
14
|
+
]
|
|
15
|
+
s.files = [
|
|
16
|
+
".document",
|
|
17
|
+
".gitignore",
|
|
18
|
+
"CHANGELOG",
|
|
19
|
+
"LICENSE",
|
|
20
|
+
"README.md",
|
|
21
|
+
"Rakefile",
|
|
22
|
+
"VERSION",
|
|
23
|
+
"active_hash.gemspec",
|
|
24
|
+
"lib/active_file/base.rb",
|
|
25
|
+
"lib/active_hash.rb",
|
|
26
|
+
"lib/active_hash/base.rb",
|
|
27
|
+
"lib/active_yaml/base.rb",
|
|
28
|
+
"spec/active_file/base_spec.rb",
|
|
29
|
+
"spec/active_hash/base_spec.rb",
|
|
30
|
+
"spec/active_yaml/base_spec.rb",
|
|
31
|
+
"spec/active_yaml/sample.yml",
|
|
32
|
+
"spec/spec_helper.rb"
|
|
33
|
+
]
|
|
34
|
+
s.homepage = %q{http://github.com/zilkey/active_hash}
|
|
35
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
|
36
|
+
s.require_paths = ["lib"]
|
|
37
|
+
s.rubygems_version = %q{1.3.3}
|
|
38
|
+
s.summary = %q{An ActiveRecord-like model that uses a hash as a datasource}
|
|
39
|
+
s.test_files = [
|
|
40
|
+
"spec/active_file/base_spec.rb",
|
|
41
|
+
"spec/active_hash/base_spec.rb",
|
|
42
|
+
"spec/active_yaml/base_spec.rb",
|
|
43
|
+
"spec/spec_helper.rb"
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
if s.respond_to? :specification_version then
|
|
47
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
|
48
|
+
s.specification_version = 3
|
|
49
|
+
|
|
50
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
|
51
|
+
s.add_runtime_dependency(%q<activesupport>, [">= 0"])
|
|
52
|
+
else
|
|
53
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
|
54
|
+
end
|
|
55
|
+
else
|
|
56
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
|
57
|
+
end
|
|
58
|
+
end
|
data/lib/active_file/base.rb
CHANGED
|
@@ -33,8 +33,6 @@ module ActiveFile
|
|
|
33
33
|
raise "Override Me"
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
protected :load_file
|
|
37
|
-
|
|
38
36
|
def extension
|
|
39
37
|
raise "Override Me"
|
|
40
38
|
end
|
|
@@ -42,13 +40,11 @@ module ActiveFile
|
|
|
42
40
|
protected :extension
|
|
43
41
|
|
|
44
42
|
def full_path
|
|
45
|
-
root_path = read_inheritable_attribute(:root_path) ||
|
|
43
|
+
root_path = read_inheritable_attribute(:root_path) || Dir.pwd
|
|
46
44
|
filename = read_inheritable_attribute(:filename) || name.tableize
|
|
47
45
|
File.join(root_path, "#{filename}.#{extension}")
|
|
48
46
|
end
|
|
49
47
|
|
|
50
|
-
private :full_path
|
|
51
|
-
|
|
52
48
|
def should_reload?
|
|
53
49
|
if (mtime = File.mtime(full_path)) == read_inheritable_attribute(:cached_mtime)
|
|
54
50
|
false
|
data/lib/active_hash/base.rb
CHANGED
|
@@ -9,7 +9,12 @@ module ActiveHash
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def all
|
|
12
|
-
@records
|
|
12
|
+
unless @records
|
|
13
|
+
records = read_inheritable_attribute(:data)
|
|
14
|
+
@records = records.collect {|hash| new(hash)}
|
|
15
|
+
auto_assign_fields( records )
|
|
16
|
+
end
|
|
17
|
+
@records
|
|
13
18
|
end
|
|
14
19
|
|
|
15
20
|
def count
|
|
@@ -48,25 +53,33 @@ module ActiveHash
|
|
|
48
53
|
end
|
|
49
54
|
|
|
50
55
|
def define_getter_method(field, default_value)
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
unless instance_methods.include?(field.to_s)
|
|
57
|
+
define_method(field) do
|
|
58
|
+
attributes[field] || default_value
|
|
59
|
+
end
|
|
53
60
|
end
|
|
54
61
|
end
|
|
55
62
|
|
|
56
63
|
private :define_getter_method
|
|
57
64
|
|
|
58
65
|
def define_interrogator_method(field)
|
|
59
|
-
|
|
60
|
-
|
|
66
|
+
method_name = "#{field}?"
|
|
67
|
+
unless instance_methods.include?(method_name)
|
|
68
|
+
define_method(method_name) do
|
|
69
|
+
attributes[field].present?
|
|
70
|
+
end
|
|
61
71
|
end
|
|
62
72
|
end
|
|
63
73
|
|
|
64
74
|
private :define_interrogator_method
|
|
65
75
|
|
|
66
76
|
def define_custom_find_method(field_name)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
77
|
+
method_name = "find_by_#{field_name}"
|
|
78
|
+
unless singleton_methods.include?(method_name)
|
|
79
|
+
metaclass.instance_eval do
|
|
80
|
+
define_method(method_name) do |name|
|
|
81
|
+
all.detect {|record| record.send(field_name) == name }
|
|
82
|
+
end
|
|
70
83
|
end
|
|
71
84
|
end
|
|
72
85
|
end
|
|
@@ -74,22 +87,35 @@ module ActiveHash
|
|
|
74
87
|
private :define_custom_find_method
|
|
75
88
|
|
|
76
89
|
def define_custom_find_all_method(field_name)
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
90
|
+
method_name = "find_all_by_#{field_name}"
|
|
91
|
+
unless singleton_methods.include?(method_name)
|
|
92
|
+
metaclass.instance_eval do
|
|
93
|
+
unless singleton_methods.include?(method_name)
|
|
94
|
+
define_method(method_name) do |name|
|
|
95
|
+
all.select {|record| record.send(field_name) == name }
|
|
96
|
+
end
|
|
97
|
+
end
|
|
80
98
|
end
|
|
81
99
|
end
|
|
82
100
|
end
|
|
83
101
|
|
|
84
102
|
private :define_custom_find_all_method
|
|
85
103
|
|
|
86
|
-
def
|
|
87
|
-
|
|
88
|
-
|
|
104
|
+
def auto_assign_fields(array_of_hashes)
|
|
105
|
+
array_of_hashes.inject([]) do |array, row|
|
|
106
|
+
row.symbolize_keys!
|
|
107
|
+
row.keys.each do |key|
|
|
108
|
+
unless key.to_s == "id"
|
|
109
|
+
array << key
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
array
|
|
113
|
+
end.uniq.each do |key|
|
|
114
|
+
field key
|
|
89
115
|
end
|
|
90
116
|
end
|
|
91
117
|
|
|
92
|
-
private :
|
|
118
|
+
private :auto_assign_fields
|
|
93
119
|
|
|
94
120
|
end
|
|
95
121
|
|
data/lib/active_yaml/base.rb
CHANGED
|
@@ -70,6 +70,16 @@ describe ActiveFile::Base do
|
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
+
describe ".full_path" do
|
|
74
|
+
it "defaults to the directory of the calling file" do
|
|
75
|
+
class FileShouldBeHere < ActiveFile::Base
|
|
76
|
+
def self.extension() "foo" end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
FileShouldBeHere.full_path.should == "#{Dir.pwd}/file_should_be_heres.foo"
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
73
83
|
describe ".all" do
|
|
74
84
|
before do
|
|
75
85
|
class MyClass
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
require 'spec/spec_helper'
|
|
2
2
|
|
|
3
|
-
describe ActiveHash
|
|
3
|
+
describe ActiveHash, "Base" do
|
|
4
4
|
|
|
5
5
|
before do
|
|
6
6
|
class Country < ActiveHash::Base
|
|
7
7
|
end
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
+
after do
|
|
11
|
+
Object.send :remove_const, :Country
|
|
12
|
+
end
|
|
13
|
+
|
|
10
14
|
describe ".fields" do
|
|
11
15
|
before do
|
|
12
16
|
Country.fields :name, :iso_name
|
|
@@ -411,4 +415,55 @@ describe ActiveHash::Base do
|
|
|
411
415
|
end
|
|
412
416
|
end
|
|
413
417
|
|
|
418
|
+
describe "auto-discovery of fields" do
|
|
419
|
+
it "dynamically creates fields for all keys in the hash" do
|
|
420
|
+
Country.data = [
|
|
421
|
+
{:field1 => "foo"},
|
|
422
|
+
{:field2 => "bar"},
|
|
423
|
+
{:field3 => "biz"}
|
|
424
|
+
]
|
|
425
|
+
|
|
426
|
+
Country.all
|
|
427
|
+
|
|
428
|
+
[:field1, :field2, :field3].each do |field|
|
|
429
|
+
Country.should respond_to("find_by_#{field}")
|
|
430
|
+
Country.should respond_to("find_all_by_#{field}")
|
|
431
|
+
Country.new.should respond_to(field)
|
|
432
|
+
Country.new.should respond_to("#{field}?")
|
|
433
|
+
end
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
it "doesn't override methods already defined" do
|
|
437
|
+
Country.class_eval do
|
|
438
|
+
class << self
|
|
439
|
+
def find_by_name(name)
|
|
440
|
+
"find_by_name defined manually"
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
def find_all_by_name(name)
|
|
444
|
+
"find_all_by_name defined manually"
|
|
445
|
+
end
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
def name
|
|
449
|
+
"name defined manually"
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
def name?
|
|
453
|
+
"name? defined manually"
|
|
454
|
+
end
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
Country.data = [
|
|
458
|
+
{:name => "foo"}
|
|
459
|
+
]
|
|
460
|
+
|
|
461
|
+
Country.all
|
|
462
|
+
Country.find_by_name("foo").should == "find_by_name defined manually"
|
|
463
|
+
Country.find_all_by_name("foo").should == "find_all_by_name defined manually"
|
|
464
|
+
Country.new.name.should == "name defined manually"
|
|
465
|
+
Country.new.name?.should == "name? defined manually"
|
|
466
|
+
end
|
|
467
|
+
end
|
|
468
|
+
|
|
414
469
|
end
|
data/spec/active_yaml/sample.yml
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
- id: 1
|
|
2
2
|
name: US
|
|
3
|
+
independence_date: 1776-07-04
|
|
4
|
+
created_at: Wed Jul 22 22:41:44 -0400 2009
|
|
5
|
+
custom_field_1: value1
|
|
3
6
|
- id: 2
|
|
4
7
|
name: Canada
|
|
8
|
+
independence_date: 1867-07-01
|
|
9
|
+
created_at: Wed Jul 22 22:41:44 -0400 2009
|
|
10
|
+
custom_field_2: value2
|
|
5
11
|
- id: 3
|
|
6
12
|
name: Mexico
|
|
13
|
+
independence_date: 1810-09-16
|
|
14
|
+
created_at: Wed Jul 22 22:41:44 -0400 2009
|
|
15
|
+
custom_field_3: value3
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: zilkey-active_hash
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jeff Dean
|
|
@@ -10,7 +10,7 @@ autorequire:
|
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
12
|
|
|
13
|
-
date: 2009-07-
|
|
13
|
+
date: 2009-07-23 00:00:00 -07:00
|
|
14
14
|
default_executable:
|
|
15
15
|
dependencies:
|
|
16
16
|
- !ruby/object:Gem::Dependency
|
|
@@ -35,10 +35,12 @@ extra_rdoc_files:
|
|
|
35
35
|
files:
|
|
36
36
|
- .document
|
|
37
37
|
- .gitignore
|
|
38
|
+
- CHANGELOG
|
|
38
39
|
- LICENSE
|
|
39
40
|
- README.md
|
|
40
41
|
- Rakefile
|
|
41
42
|
- VERSION
|
|
43
|
+
- active_hash.gemspec
|
|
42
44
|
- lib/active_file/base.rb
|
|
43
45
|
- lib/active_hash.rb
|
|
44
46
|
- lib/active_hash/base.rb
|