active_hash 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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