honkster-active_hash 0.7.3

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/geminstaller.yml ADDED
@@ -0,0 +1,13 @@
1
+ defaults:
2
+ install_options: --source=http://gemcutter.org --source=http://gems.rubyforge.org --include-dependencies --no-ri --no-rdoc
3
+ gems:
4
+ - name: acts_as_fu
5
+ version: 0.0.5
6
+ - name: activesupport
7
+ version: >= 2.2.2
8
+ - name: rspec
9
+ version: >= 1.2.8
10
+ - name: fixjour
11
+ version: 0.2.0
12
+ - name: jeweler
13
+ version: 1.2.1
@@ -0,0 +1,50 @@
1
+ module ActiveFile
2
+
3
+ class Base < ActiveHash::Base
4
+ class_inheritable_accessor :filename, :root_path, :data_loaded
5
+
6
+ class << self
7
+
8
+ def all
9
+ reload unless data_loaded
10
+ super
11
+ end
12
+
13
+ def delete_all
14
+ self.data_loaded = true
15
+ super
16
+ end
17
+
18
+ def reload(foo = true)
19
+ self.data_loaded = true
20
+ self.data = load_file
21
+ end
22
+
23
+ def set_filename(name)
24
+ write_inheritable_attribute :filename, name
25
+ end
26
+
27
+ def set_root_path(path)
28
+ write_inheritable_attribute :root_path, path
29
+ end
30
+
31
+ def load_file
32
+ raise "Override Me"
33
+ end
34
+
35
+ def full_path
36
+ root_path = read_inheritable_attribute(:root_path) || Dir.pwd
37
+ filename = read_inheritable_attribute(:filename) || name.tableize
38
+ File.join(root_path, "#{filename}.#{extension}")
39
+ end
40
+
41
+ def extension
42
+ raise "Override Me"
43
+ end
44
+
45
+ protected :extension
46
+
47
+ end
48
+ end
49
+
50
+ end
@@ -0,0 +1,5 @@
1
+ require 'activesupport'
2
+ require 'active_hash/base'
3
+ require 'active_file/base'
4
+ require 'active_yaml/base'
5
+ require 'associations/associations'
@@ -0,0 +1,265 @@
1
+ module ActiveHash
2
+ class Base
3
+ class_inheritable_accessor :data
4
+ class << self
5
+ attr_reader :field_names
6
+
7
+ def data=(array_of_hashes)
8
+ @records = nil
9
+ write_inheritable_attribute(:data, array_of_hashes)
10
+ if array_of_hashes
11
+ auto_assign_fields( array_of_hashes )
12
+ array_of_hashes.each do |hash|
13
+ insert new(hash)
14
+ end
15
+ end
16
+ end
17
+
18
+ def insert(record)
19
+ @records ||= []
20
+ record.attributes[:id] ||= next_id
21
+ @records << record
22
+ end
23
+
24
+ def next_id
25
+ max_record = all.max {|a, b| a.id <=> b.id }
26
+ if max_record.nil?
27
+ 1
28
+ elsif max_record.id.is_a?(Numeric)
29
+ max_record.id.succ
30
+ end
31
+ end
32
+
33
+ def create(attributes = {})
34
+ record = new(attributes)
35
+ record.save
36
+ record
37
+ end
38
+
39
+ def create!(attributes = {})
40
+ record = new(attributes)
41
+ record.save!
42
+ record
43
+ end
44
+
45
+ def all
46
+ @records || []
47
+ end
48
+
49
+ def count
50
+ all.length
51
+ end
52
+
53
+ def transaction
54
+ yield
55
+ rescue ActiveRecord::Rollback
56
+
57
+ end
58
+
59
+ def delete_all
60
+ @records = []
61
+ end
62
+
63
+ def find(id, *args)
64
+ case id
65
+ when :all
66
+ all
67
+ when Array
68
+ all.select {|record| id.map(&:to_i).include?(record.id) }
69
+ else
70
+ find_by_id(id)
71
+ end
72
+ end
73
+
74
+ def find_by_id(id)
75
+ all.detect {|record| record.id == id.to_i}
76
+ end
77
+
78
+ delegate :first, :last, :to => :all
79
+
80
+ def fields(*args)
81
+ options = args.extract_options!
82
+ args.each do |field|
83
+ field(field, options)
84
+ end
85
+ end
86
+
87
+ def field(field_name, options = {})
88
+ @field_names ||= []
89
+ @field_names << field_name
90
+
91
+ define_getter_method(field_name, options[:default])
92
+ define_setter_method(field_name)
93
+ define_interrogator_method(field_name)
94
+ define_custom_find_method(field_name)
95
+ define_custom_find_all_method(field_name)
96
+ end
97
+
98
+ def respond_to?(method_name, include_private=false)
99
+ super ||
100
+ begin
101
+ config = configuration_for_custom_finder(method_name)
102
+ config && config[:fields].all? do |field|
103
+ field_names.include?(field.to_sym) || field.to_sym == :id
104
+ end
105
+ end
106
+ end
107
+
108
+ def method_missing(method_name, *args)
109
+ return super unless respond_to? method_name
110
+
111
+ config = configuration_for_custom_finder(method_name)
112
+ attribute_pairs = config[:fields].zip(args)
113
+ matches = all.select { |base| attribute_pairs.all? { |field, value| base.send(field).to_s == value.to_s } }
114
+ config[:all?] ? matches : matches.first
115
+ end
116
+
117
+ def configuration_for_custom_finder(finder_name)
118
+ if finder_name.to_s.match(/^find_(all_)?by_(.*)/)
119
+ {
120
+ :all? => !!$1,
121
+ :fields => $2.split('_and_')
122
+ }
123
+ end
124
+ end
125
+
126
+ private :configuration_for_custom_finder
127
+
128
+ def define_getter_method(field, default_value)
129
+ unless instance_methods.include?(field.to_s)
130
+ define_method(field) do
131
+ attributes[field].nil? ? default_value : attributes[field]
132
+ end
133
+ end
134
+ end
135
+
136
+ private :define_getter_method
137
+
138
+ def define_setter_method(field)
139
+ method_name = "#{field}="
140
+ unless instance_methods.include?(method_name)
141
+ define_method(method_name) do |new_val|
142
+ attributes[field] = new_val
143
+ end
144
+ end
145
+ end
146
+
147
+ private :define_setter_method
148
+
149
+ def define_interrogator_method(field)
150
+ method_name = "#{field}?"
151
+ unless instance_methods.include?(method_name)
152
+ define_method(method_name) do
153
+ send(field).present?
154
+ end
155
+ end
156
+ end
157
+
158
+ private :define_interrogator_method
159
+
160
+ def define_custom_find_method(field_name)
161
+ method_name = "find_by_#{field_name}"
162
+ unless singleton_methods.include?(method_name)
163
+ metaclass.instance_eval do
164
+ define_method(method_name) do |name|
165
+ all.detect {|record| record.send(field_name) == name }
166
+ end
167
+ end
168
+ end
169
+ end
170
+
171
+ private :define_custom_find_method
172
+
173
+ def define_custom_find_all_method(field_name)
174
+ method_name = "find_all_by_#{field_name}"
175
+ unless singleton_methods.include?(method_name)
176
+ metaclass.instance_eval do
177
+ unless singleton_methods.include?(method_name)
178
+ define_method(method_name) do |name|
179
+ all.select {|record| record.send(field_name) == name }
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end
185
+
186
+ private :define_custom_find_all_method
187
+
188
+ def auto_assign_fields(array_of_hashes)
189
+ (array_of_hashes || []).inject([]) do |array, row|
190
+ row.symbolize_keys!
191
+ row.keys.each do |key|
192
+ unless key.to_s == "id"
193
+ array << key
194
+ end
195
+ end
196
+ array
197
+ end.uniq.each do |key|
198
+ field key
199
+ end
200
+ end
201
+
202
+ private :auto_assign_fields
203
+
204
+ # Needed for ActiveRecord polymorphic associations
205
+ def base_class
206
+ ActiveHash::Base
207
+ end
208
+
209
+ end
210
+
211
+ attr_reader :attributes
212
+
213
+ def initialize(options = {})
214
+ options.symbolize_keys!
215
+ @attributes = options
216
+ options.each do |key, value|
217
+ send "#{key}=", value
218
+ end
219
+ end
220
+
221
+ def id
222
+ attributes[:id] ? attributes[:id] : nil
223
+ end
224
+
225
+ def id=(id)
226
+ attributes[:id] = id
227
+ end
228
+
229
+ alias quoted_id id
230
+
231
+ def new_record?
232
+ ! self.class.all.include?(self)
233
+ end
234
+
235
+ def readonly?
236
+ true
237
+ end
238
+
239
+ def to_param
240
+ id.to_s
241
+ end
242
+
243
+ def eql?(other)
244
+ other.instance_of?(self.class) and not id.nil? and (id == other.id)
245
+ end
246
+
247
+ alias == eql?
248
+
249
+ def hash
250
+ id.hash
251
+ end
252
+
253
+ def save
254
+ self.class.insert(self)
255
+ true
256
+ end
257
+
258
+ alias save! save
259
+
260
+ def valid?
261
+ true
262
+ end
263
+
264
+ end
265
+ end
@@ -0,0 +1,24 @@
1
+ module ActiveYaml
2
+
3
+ class Base < ActiveFile::Base
4
+ class << self
5
+ def load_file
6
+ if (data = raw_data).is_a?(Array)
7
+ data
8
+ else
9
+ data.values
10
+ end
11
+ end
12
+
13
+ def raw_data
14
+ YAML.load_file(full_path)
15
+ end
16
+
17
+ def extension
18
+ "yml"
19
+ end
20
+
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,40 @@
1
+ module ActiveHash
2
+ module Associations
3
+
4
+ def self.included(base)
5
+ base.send(:extend, ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def has_many(association_id, options = {})
10
+
11
+ define_method(association_id) do
12
+ options = {
13
+ :class_name => association_id.to_s.classify,
14
+ :foreign_key => self.class.to_s.foreign_key
15
+ }.merge(options)
16
+
17
+ options[:class_name].constantize.send("find_all_by_#{options[:foreign_key]}", id)
18
+ end
19
+
20
+ end
21
+
22
+ def belongs_to(association_id, options = {})
23
+
24
+ options = {
25
+ :class_name => association_id.to_s.classify,
26
+ :foreign_key => association_id.to_s.foreign_key
27
+ }.merge(options)
28
+
29
+ define_method(association_id) do
30
+ options[:class_name].constantize.find(send(options[:foreign_key]))
31
+ end
32
+
33
+ define_method("#{association_id}=") do |new_value|
34
+ attributes[ options[:foreign_key].to_sym ] = new_value.id
35
+ end
36
+
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,83 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ActiveFile::Base do
4
+ before do
5
+ class Country < ActiveFile::Base
6
+ end
7
+ end
8
+
9
+ after do
10
+ Object.send :remove_const, :Country
11
+ end
12
+
13
+ describe ".filename=" do
14
+ before do
15
+ Country.filename = "foo-izzle"
16
+
17
+ class Bar < ActiveFile::Base
18
+ self.filename = "bar-izzle"
19
+ end
20
+ end
21
+
22
+ it "sets the filename on a per-subclass basis" do
23
+ Country.filename.should == "foo-izzle"
24
+ Bar.filename.should == "bar-izzle"
25
+ end
26
+ end
27
+
28
+ describe ".set_filename" do
29
+ before do
30
+ Country.set_filename "foo-izzle"
31
+
32
+ class Bar < ActiveFile::Base
33
+ set_filename "bar-izzle"
34
+ end
35
+ end
36
+
37
+ it "sets the filename on a per-subclass basis" do
38
+ Country.filename.should == "foo-izzle"
39
+ Bar.filename.should == "bar-izzle"
40
+ end
41
+ end
42
+
43
+ describe ".root_path=" do
44
+ before do
45
+ Country.root_path = "foo-izzle"
46
+
47
+ class Bar < ActiveFile::Base
48
+ self.root_path = "bar-izzle"
49
+ end
50
+ end
51
+
52
+ it "sets the root_path on a per-subclass basis" do
53
+ Country.root_path.should == "foo-izzle"
54
+ Bar.root_path.should == "bar-izzle"
55
+ end
56
+ end
57
+
58
+ describe ".set_root_path" do
59
+ before do
60
+ Country.set_root_path "foo-izzle"
61
+
62
+ class Bar < ActiveFile::Base
63
+ set_root_path "bar-izzle"
64
+ end
65
+ end
66
+
67
+ it "sets the root_path on a per-subclass basis" do
68
+ Country.root_path.should == "foo-izzle"
69
+ Bar.root_path.should == "bar-izzle"
70
+ end
71
+ end
72
+
73
+ describe ".full_path" do
74
+ it "defaults to the directory of the calling file" do
75
+ class Country
76
+ def self.extension() "foo" end
77
+ end
78
+
79
+ Country.full_path.should == "#{Dir.pwd}/countries.foo"
80
+ end
81
+ end
82
+
83
+ end