active_hash 0.6.1 → 0.7.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 CHANGED
@@ -1,3 +1,14 @@
1
+ 2009-10-12
2
+ - auto-assign fields after calling data= instead of after calling .all
3
+ - remove require 'rubygems', so folks with non-gem setups can still use AH
4
+ - added more specific activesupport dependency to ensure that metaclass is available
5
+ - AH no longer calls to_i on ids. If you pass in a string as an id, you'll get a string back
6
+ - Fancy finders, such as find_all_by_id_and_name, will compare the to_s values of the fields, so you can pass in strings
7
+ - You can now use ActiveHash models as the parents of polymorphic belongs_to associations
8
+ - save, save!, create and create! now add items to the in-memory collection, and naively adds autoincrementing id
9
+ - new_record? returns false if the record is part of the collection
10
+ - ActiveHash now works with Fixjour!
11
+
1
12
  2009-08-19
2
13
  - Added custom finders for multiple fields, such as .find_all_by_name_and_age
3
14
 
@@ -10,4 +21,4 @@
10
21
  - ActiveFile no longer reloads files by default
11
22
  - Added ActiveFile.reload_active_file= so you can cause ActiveFile to reload
12
23
  - Setting data to nil correctly causes .all to return an empty array
13
- - Added reload(force) method, so that you can force a reload from files in ActiveFile, useful for tests
24
+ - Added reload(force) method, so that you can force a reload from files in ActiveFile, useful for tests
data/README.md CHANGED
@@ -193,10 +193,6 @@ NOTE: By default, .full_path refers to the current working directory. In a rai
193
193
 
194
194
  Written by Jeff Dean, Mike Dalessio and Ben Woosley
195
195
 
196
- ## Development
197
-
198
- The only thing I think I'd really like to add here is support for typecasting the fields.
199
-
200
196
  == Copyright
201
197
 
202
198
  Copyright (c) 2009 Jeff Dean. See LICENSE for details.
data/Rakefile CHANGED
@@ -5,12 +5,11 @@ begin
5
5
  require 'jeweler'
6
6
  Jeweler::Tasks.new do |gem|
7
7
  gem.name = "active_hash"
8
- gem.summary = %Q{An ActiveRecord-like model that uses a hash as a datasource}
8
+ gem.summary = %Q{An ActiveRecord-like model that uses a hash or file as a datasource}
9
9
  gem.email = "jeff@zilkey.com"
10
10
  gem.homepage = "http://github.com/zilkey/active_hash"
11
11
  gem.authors = ["Jeff Dean", "Mike Dalessio", "Corey Innis", "Peter Jaros"]
12
- gem.add_dependency('activesupport')
13
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
12
+ gem.add_dependency('activesupport', [">= 2.2.2"])
14
13
  end
15
14
 
16
15
  rescue LoadError
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.1
1
+ 0.7.0
data/active_hash.gemspec CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{active_hash}
5
- s.version = "0.6.1"
5
+ s.version = "0.7.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Jeff Dean", "Mike Dalessio", "Corey Innis", "Peter Jaros"]
9
- s.date = %q{2009-08-19}
9
+ s.date = %q{2009-10-13}
10
10
  s.email = %q{jeff@zilkey.com}
11
11
  s.extra_rdoc_files = [
12
12
  "LICENSE",
@@ -21,6 +21,7 @@ Gem::Specification.new do |s|
21
21
  "Rakefile",
22
22
  "VERSION",
23
23
  "active_hash.gemspec",
24
+ "geminstaller.yml",
24
25
  "lib/active_file/base.rb",
25
26
  "lib/active_hash.rb",
26
27
  "lib/active_hash/base.rb",
@@ -31,12 +32,11 @@ Gem::Specification.new do |s|
31
32
  "spec/active_yaml/sample.yml",
32
33
  "spec/spec_helper.rb"
33
34
  ]
34
- s.has_rdoc = true
35
35
  s.homepage = %q{http://github.com/zilkey/active_hash}
36
36
  s.rdoc_options = ["--charset=UTF-8"]
37
37
  s.require_paths = ["lib"]
38
- s.rubygems_version = %q{1.3.1}
39
- s.summary = %q{An ActiveRecord-like model that uses a hash as a datasource}
38
+ s.rubygems_version = %q{1.3.3}
39
+ s.summary = %q{An ActiveRecord-like model that uses a hash or file as a datasource}
40
40
  s.test_files = [
41
41
  "spec/active_file/base_spec.rb",
42
42
  "spec/active_hash/base_spec.rb",
@@ -46,14 +46,14 @@ Gem::Specification.new do |s|
46
46
 
47
47
  if s.respond_to? :specification_version then
48
48
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
49
- s.specification_version = 2
49
+ s.specification_version = 3
50
50
 
51
51
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
52
- s.add_runtime_dependency(%q<activesupport>, [">= 0"])
52
+ s.add_runtime_dependency(%q<activesupport>, [">= 2.2.2"])
53
53
  else
54
- s.add_dependency(%q<activesupport>, [">= 0"])
54
+ s.add_dependency(%q<activesupport>, [">= 2.2.2"])
55
55
  end
56
56
  else
57
- s.add_dependency(%q<activesupport>, [">= 0"])
57
+ s.add_dependency(%q<activesupport>, [">= 2.2.2"])
58
58
  end
59
59
  end
data/geminstaller.yml ADDED
@@ -0,0 +1,11 @@
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
data/lib/active_hash.rb CHANGED
@@ -1,5 +1,4 @@
1
- require 'rubygems'
2
1
  require 'activesupport'
3
2
  require 'active_hash/base'
4
3
  require 'active_file/base'
5
- require 'active_yaml/base'
4
+ require 'active_yaml/base'
@@ -7,13 +7,40 @@ module ActiveHash
7
7
  def data=(array_of_hashes)
8
8
  @records = nil
9
9
  write_inheritable_attribute(:data, array_of_hashes)
10
+ auto_assign_fields( array_of_hashes )
11
+ end
12
+
13
+ def insert(record)
14
+ @records ||= []
15
+ record.attributes[:id] ||= next_id
16
+ @records << record
17
+ end
18
+
19
+ def next_id
20
+ max_record = all.max {|a, b| a.id <=> b.id }
21
+ if max_record.nil?
22
+ 1
23
+ elsif max_record.id.is_a?(Numeric)
24
+ max_record.id.succ
25
+ end
26
+ end
27
+
28
+ def create(attributes)
29
+ record = new(attributes)
30
+ record.save
31
+ record
32
+ end
33
+
34
+ def create!(attributes)
35
+ record = new(attributes)
36
+ record.save!
37
+ record
10
38
  end
11
39
 
12
40
  def all
13
41
  unless @records
14
42
  records = read_inheritable_attribute(:data) || []
15
43
  @records = records.collect {|hash| new(hash)}
16
- auto_assign_fields( records )
17
44
  end
18
45
  @records
19
46
  end
@@ -22,6 +49,12 @@ module ActiveHash
22
49
  all.length
23
50
  end
24
51
 
52
+ def transaction
53
+ yield
54
+ rescue ActiveRecord::Rollback
55
+
56
+ end
57
+
25
58
  def find(id, *args)
26
59
  case id
27
60
  when :all
@@ -60,7 +93,9 @@ module ActiveHash
60
93
  super ||
61
94
  begin
62
95
  config = configuration_for_custom_finder(method_name)
63
- config && config[:fields].all? { |field| field_names.include?(field.to_sym) }
96
+ config && config[:fields].all? do |field|
97
+ field_names.include?(field.to_sym) || field.to_sym == :id
98
+ end
64
99
  end
65
100
  end
66
101
 
@@ -69,7 +104,7 @@ module ActiveHash
69
104
 
70
105
  config = configuration_for_custom_finder(method_name)
71
106
  attribute_pairs = config[:fields].zip(args)
72
- matches = all.select { |base| attribute_pairs.all? { |field, value| base.send(field) == value } }
107
+ matches = all.select { |base| attribute_pairs.all? { |field, value| base.send(field).to_s == value.to_s } }
73
108
  config[:all?] ? matches : matches.first
74
109
  end
75
110
 
@@ -82,6 +117,8 @@ module ActiveHash
82
117
  end
83
118
  end
84
119
 
120
+ private :configuration_for_custom_finder
121
+
85
122
  def define_getter_method(field, default_value)
86
123
  unless instance_methods.include?(field.to_s)
87
124
  define_method(field) do
@@ -96,7 +133,7 @@ module ActiveHash
96
133
  method_name = "#{field}?"
97
134
  unless instance_methods.include?(method_name)
98
135
  define_method(method_name) do
99
- attributes[field].present?
136
+ send(field).present?
100
137
  end
101
138
  end
102
139
  end
@@ -132,7 +169,7 @@ module ActiveHash
132
169
  private :define_custom_find_all_method
133
170
 
134
171
  def auto_assign_fields(array_of_hashes)
135
- array_of_hashes.inject([]) do |array, row|
172
+ (array_of_hashes || []).inject([]) do |array, row|
136
173
  row.symbolize_keys!
137
174
  row.keys.each do |key|
138
175
  unless key.to_s == "id"
@@ -147,6 +184,11 @@ module ActiveHash
147
184
 
148
185
  private :auto_assign_fields
149
186
 
187
+ # Needed for ActiveRecord polymorphic associations
188
+ def base_class
189
+ ActiveHash::Base
190
+ end
191
+
150
192
  end
151
193
 
152
194
  attr_reader :attributes
@@ -157,13 +199,13 @@ module ActiveHash
157
199
  end
158
200
 
159
201
  def id
160
- attributes[:id] ? attributes[:id].to_i : nil
202
+ attributes[:id] ? attributes[:id] : nil
161
203
  end
162
204
 
163
205
  alias quoted_id id
164
206
 
165
207
  def new_record?
166
- false
208
+ ! self.class.all.include?(self)
167
209
  end
168
210
 
169
211
  def readonly?
@@ -184,5 +226,16 @@ module ActiveHash
184
226
  id.hash
185
227
  end
186
228
 
229
+ def save
230
+ self.class.insert(self)
231
+ true
232
+ end
233
+
234
+ alias save! save
235
+
236
+ def valid?
237
+ true
238
+ end
239
+
187
240
  end
188
241
  end
@@ -185,7 +185,7 @@ describe ActiveHash, "Base" do
185
185
  end
186
186
 
187
187
  it "returns all matching ids" do
188
- Country.find([1,3]).should =~ [Country.new(:id => 1), Country.new(:id => 3)]
188
+ Country.find([1, 3]).should =~ [Country.new(:id => 1), Country.new(:id => 3)]
189
189
  end
190
190
  end
191
191
  end
@@ -289,6 +289,12 @@ describe ActiveHash, "Base" do
289
289
  end
290
290
  end
291
291
 
292
+ describe "with a match based on to_s" do
293
+ it "returns the first matching record" do
294
+ Country.find_by_name_and_id("Canada", "13").id.should == 13
295
+ end
296
+ end
297
+
292
298
  describe "without a match" do
293
299
  it "returns nil" do
294
300
  Country.find_by_name_and_monarch("US", "The Crown of England").should be_nil
@@ -322,7 +328,6 @@ describe ActiveHash, "Base" do
322
328
  end
323
329
  end
324
330
 
325
-
326
331
  describe "#attributes" do
327
332
  it "returns the hash passed in the initializer" do
328
333
  country = Country.new(:foo => :bar)
@@ -381,7 +386,7 @@ describe ActiveHash, "Base" do
381
386
 
382
387
  it "returns false if the given attribute is blank" do
383
388
  country = Country.new(:name => " ")
384
- country.should_not be_name
389
+ country.name?.should == false
385
390
  end
386
391
 
387
392
  it "returns false if the given attribute was not passed" do
@@ -391,12 +396,6 @@ describe ActiveHash, "Base" do
391
396
  end
392
397
 
393
398
  describe "#id" do
394
- context "when passed an id" do
395
- it "returns the id as an integer" do
396
- country = Country.new :id => "1"
397
- country.id.should == 1
398
- end
399
- end
400
399
  context "when not passed an id" do
401
400
  it "returns nil" do
402
401
  country = Country.new
@@ -405,12 +404,6 @@ describe ActiveHash, "Base" do
405
404
  end
406
405
  end
407
406
 
408
- describe "#new_record?" do
409
- it "should be false" do
410
- Country.new.should_not be_new_record
411
- end
412
- end
413
-
414
407
  describe "#quoted_id" do
415
408
  it "should return id" do
416
409
  Country.new(:id => 2).quoted_id.should == 2
@@ -495,8 +488,6 @@ describe ActiveHash, "Base" do
495
488
  {:field3 => "biz"}
496
489
  ]
497
490
 
498
- Country.all
499
-
500
491
  [:field1, :field2, :field3].each do |field|
501
492
  Country.should respond_to("find_by_#{field}")
502
493
  Country.should respond_to("find_all_by_#{field}")
@@ -538,4 +529,188 @@ describe ActiveHash, "Base" do
538
529
  end
539
530
  end
540
531
 
541
- end
532
+ describe "using with belongs_to in ActiveRecord" do
533
+ before do
534
+ Country.data = [
535
+ {:id => 1, :name => "foo"}
536
+ ]
537
+
538
+ build_model :books do
539
+ text :subject_type
540
+ integer :subject_id
541
+ belongs_to :subject, :polymorphic => true
542
+ belongs_to :country
543
+ end
544
+ end
545
+
546
+ it "should be possible to use it as a parent" do
547
+ book = Book.new
548
+ book.country = Country.first
549
+ book.country.should == Country.first
550
+ end
551
+
552
+ it "should be possible to use it as a polymorphic parent" do
553
+ book = Book.new
554
+ book.subject = Country.first
555
+ book.subject.should == Country.first
556
+ end
557
+
558
+ end
559
+
560
+ describe "#save" do
561
+
562
+ before do
563
+ Country.field :name
564
+ end
565
+
566
+ it "adds the new object to the data collection" do
567
+ Country.all.should be_empty
568
+ country = Country.new :id => 1, :name => "foo"
569
+ country.save.should be_true
570
+ Country.all.should == [country]
571
+ end
572
+
573
+ it "adds the new object to the data collection" do
574
+ Country.all.should be_empty
575
+ country = Country.new :id => 1, :name => "foo"
576
+ country.save!.should be_true
577
+ Country.all.should == [country]
578
+ end
579
+
580
+ end
581
+
582
+ describe ".create" do
583
+
584
+ before do
585
+ Country.field :name
586
+ end
587
+
588
+ it "adds the new object to the data collection" do
589
+ Country.all.should be_empty
590
+ country = Country.create :id => 1, :name => "foo"
591
+ country.id.should == 1
592
+ country.name.should == "foo"
593
+ Country.all.should == [country]
594
+ end
595
+
596
+ it "adds an auto-incrementing id if the id is nil" do
597
+ country1 = Country.new :name => "foo"
598
+ country1.save
599
+ country1.id.should == 1
600
+
601
+ country2 = Country.new :name => "bar"
602
+ country2.save
603
+ country2.id.should == 2
604
+ end
605
+
606
+ it "does not add auto-incrementing id if the id is present" do
607
+ country1 = Country.new :id => 456, :name => "foo"
608
+ country1.save
609
+ country1.id.should == 456
610
+ end
611
+
612
+ it "does not blow up with strings" do
613
+ country1 = Country.new :id => "foo", :name => "foo"
614
+ country1.save
615
+ country1.id.should == "foo"
616
+
617
+ country2 = Country.new :name => "foo"
618
+ country2.save
619
+ country2.id.should be_nil
620
+ end
621
+
622
+ it "adds the new object to the data collection" do
623
+ Country.all.should be_empty
624
+ country = Country.create! :id => 1, :name => "foo"
625
+ country.id.should == 1
626
+ country.name.should == "foo"
627
+ Country.all.should == [country]
628
+ end
629
+
630
+ end
631
+
632
+ describe "#valid?" do
633
+
634
+ it "should return true" do
635
+ Country.new.should be_valid
636
+ end
637
+
638
+ end
639
+
640
+ describe "#new_record?" do
641
+ before do
642
+ Country.field :name
643
+ Country.data = [
644
+ :id => 1, :name => "foo"
645
+ ]
646
+ end
647
+
648
+ it "returns false when the object is already part of the collection" do
649
+ Country.new(:id => 1).should_not be_new_record
650
+ end
651
+
652
+ it "returns true when the object is not part of the collection" do
653
+ Country.new(:id => 2).should be_new_record
654
+ end
655
+
656
+ end
657
+
658
+ describe ".transaction" do
659
+
660
+ it "execute the block given to it" do
661
+ foo = Object.new
662
+ foo.should_receive(:bar)
663
+ Country.transaction do
664
+ foo.bar
665
+ end
666
+ end
667
+
668
+ it "swallows ActiveRecord::Rollback errors" do
669
+ proc do
670
+ Country.transaction do
671
+ raise ActiveRecord::Rollback
672
+ end
673
+ end.should_not raise_error
674
+ end
675
+
676
+ it "passes other errors through" do
677
+ proc do
678
+ Country.transaction do
679
+ raise "hell"
680
+ end
681
+ end.should raise_error("hell")
682
+ end
683
+
684
+ end
685
+
686
+ describe "using with Fixjour" do
687
+
688
+ before do
689
+ Country.field :name
690
+ Fixjour do
691
+ define_builder(Country) do |klass, overrides|
692
+ klass.new(:name => 'Pat')
693
+ end
694
+ end
695
+ end
696
+
697
+ it "should verify" do
698
+ Fixjour.verify!
699
+ end
700
+
701
+ it "should work with the create builder" do
702
+ proc do
703
+ create_country
704
+ end.should change(Country, :count).by(1)
705
+ end
706
+
707
+ it "should work with the new builder" do
708
+ proc do
709
+ country = new_country :name => "foo"
710
+ country.name.should == "foo"
711
+ end.should_not change(Country, :count)
712
+ end
713
+
714
+ end
715
+
716
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,20 @@
1
1
  require 'spec'
2
+ require 'acts_as_fu'
3
+ require 'fixjour'
2
4
 
3
5
  $LOAD_PATH.unshift(File.dirname(__FILE__))
4
6
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
5
7
  require 'active_hash'
6
8
 
9
+ ActiveHash::Base.class_eval do
10
+ def self.to_ary
11
+ end
12
+
13
+ def self.to_str
14
+ end
15
+ end
16
+
7
17
  Spec::Runner.configure do |config|
8
-
18
+ config.include ActsAsFu
19
+ config.include Fixjour
9
20
  end
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: 0.6.1
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Dean
@@ -12,7 +12,7 @@ autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
14
 
15
- date: 2009-08-19 00:00:00 -04:00
15
+ date: 2009-10-13 00:00:00 -04:00
16
16
  default_executable:
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
@@ -23,7 +23,7 @@ dependencies:
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: "0"
26
+ version: 2.2.2
27
27
  version:
28
28
  description:
29
29
  email: jeff@zilkey.com
@@ -43,6 +43,7 @@ files:
43
43
  - Rakefile
44
44
  - VERSION
45
45
  - active_hash.gemspec
46
+ - geminstaller.yml
46
47
  - lib/active_file/base.rb
47
48
  - lib/active_hash.rb
48
49
  - lib/active_hash/base.rb
@@ -78,8 +79,8 @@ requirements: []
78
79
  rubyforge_project:
79
80
  rubygems_version: 1.3.3
80
81
  signing_key:
81
- specification_version: 2
82
- summary: An ActiveRecord-like model that uses a hash as a datasource
82
+ specification_version: 3
83
+ summary: An ActiveRecord-like model that uses a hash or file as a datasource
83
84
  test_files:
84
85
  - spec/active_file/base_spec.rb
85
86
  - spec/active_hash/base_spec.rb