couchrest_model 2.0.0.beta → 2.0.0.beta2

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/VERSION CHANGED
@@ -1 +1 @@
1
- 2.0.0.beta
1
+ 2.0.0.beta2
@@ -23,14 +23,15 @@ Gem::Specification.new do |s|
23
23
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
24
24
  s.require_paths = ["lib"]
25
25
 
26
- s.add_dependency(%q<couchrest>, "~> 1.1.2")
26
+ s.add_dependency(%q<couchrest>, "~> 1.1.3")
27
27
  s.add_dependency(%q<mime-types>, "~> 1.15")
28
- s.add_dependency(%q<activemodel>, "~> 3.1.0")
28
+ s.add_dependency(%q<activemodel>, "~> 3.0")
29
29
  s.add_dependency(%q<tzinfo>, "~> 0.3.22")
30
30
  s.add_development_dependency(%q<rspec>, "~> 2.6.0")
31
31
  s.add_development_dependency(%q<json>, ["~> 1.5.1"])
32
32
  s.add_development_dependency(%q<rack-test>, ">= 0.5.7")
33
33
  s.add_development_dependency("rake", ">= 0.8.0")
34
+ s.add_development_dependency("debugger", "~> 1.2.0")
34
35
  # s.add_development_dependency("jruby-openssl", ">= 0.7.3")
35
36
  end
36
37
 
data/history.md CHANGED
@@ -1,11 +1,15 @@
1
1
  # CouchRest Model Change History
2
2
 
3
- ## 2.0.0.beta - 2012-06-14
3
+ ## 2.0.0.beta2 - 2012-08-02
4
4
 
5
5
  * Added design doc migration support, including for proxied models
6
6
  * Rake tasks available for migrations
7
7
  * Rails config option now available: `config.couchrest_model.auto_update_design_docs = false`
8
8
  * Skipping 1.2 version due to design doc API changes
9
+ * Added 'couchrest_typecast' class method support for typecasting with special classes.
10
+ * Added :allow_blank option to properties so that empty strings are forced to nil.
11
+ * Modified associations to use allow_blank property
12
+ * Incorported Rails 3.2 support changes (Thanks @jodosha)
9
13
 
10
14
  ## 1.2.0.beta - 2012-06-08
11
15
 
@@ -38,7 +38,7 @@ module CouchRest
38
38
  def belongs_to(attrib, *options)
39
39
  opts = merge_belongs_to_association_options(attrib, options.first)
40
40
 
41
- property(opts[:foreign_key], opts)
41
+ property(opts[:foreign_key], String, opts)
42
42
 
43
43
  create_belongs_to_getter(attrib, opts)
44
44
  create_belongs_to_setter(attrib, opts)
@@ -88,7 +88,7 @@ module CouchRest
88
88
  opts[:foreign_key] = opts[:foreign_key].pluralize
89
89
  opts[:readonly] = true
90
90
 
91
- property(opts[:foreign_key], [], opts)
91
+ property(opts[:foreign_key], [String], opts)
92
92
 
93
93
  create_collection_of_property_setter(attrib, opts)
94
94
  create_collection_of_getter(attrib, opts)
@@ -101,8 +101,9 @@ module CouchRest
101
101
  def merge_belongs_to_association_options(attrib, options = nil)
102
102
  opts = {
103
103
  :foreign_key => attrib.to_s.singularize + '_id',
104
- :class_name => attrib.to_s.singularize.camelcase,
105
- :proxy_name => attrib.to_s.pluralize
104
+ :class_name => attrib.to_s.singularize.camelcase,
105
+ :proxy_name => attrib.to_s.pluralize,
106
+ :allow_blank => false
106
107
  }
107
108
  opts.merge!(options) if options.is_a?(Hash)
108
109
 
@@ -224,6 +225,15 @@ module CouchRest
224
225
  raise "Object cannot be added to #{casted_by.class.to_s}##{casted_by_property.to_s} collection unless saved" if obj.new?
225
226
  end
226
227
 
228
+ # Override CastedArray instantiation_and_cast method for a simpler
229
+ # version that will not try to cast the model.
230
+ def instantiate_and_cast(obj, change = true)
231
+ couchrest_parent_will_change! if change && use_dirty?
232
+ obj.casted_by = casted_by if obj.respond_to?(:casted_by)
233
+ obj.casted_by_property = casted_by_property if obj.respond_to?(:casted_by_property)
234
+ obj
235
+ end
236
+
227
237
  end
228
238
 
229
239
  end
@@ -2,7 +2,8 @@ module CouchRest
2
2
  module Model
3
3
  class Base < CouchRest::Document
4
4
 
5
- extend ActiveModel::Naming
5
+ extend ActiveModel::Naming
6
+ include ActiveModel::Conversion
6
7
 
7
8
  include CouchRest::Model::Configuration
8
9
  include CouchRest::Model::Connection
@@ -62,11 +63,6 @@ module CouchRest
62
63
  run_callbacks(:initialize) { self }
63
64
  end
64
65
 
65
- def to_key
66
- new? ? nil : [id]
67
- end
68
-
69
- alias :to_param :id
70
66
  alias :new_record? :new?
71
67
  alias :new_document? :new?
72
68
 
@@ -40,7 +40,7 @@ module CouchRest
40
40
  # with a property and update dirty status
41
41
  def write_attribute(property, value)
42
42
  prop = find_property!(property)
43
- value = prop.is_a?(String) ? value : prop.cast(self, value)
43
+ value = prop.cast(self, value)
44
44
  couchrest_attribute_will_change!(prop.name) if use_dirty? && self[prop.name] != value
45
45
  self[prop.name] = value
46
46
  end
@@ -4,7 +4,7 @@ module CouchRest::Model
4
4
 
5
5
  include ::CouchRest::Model::Typecast
6
6
 
7
- attr_reader :name, :type, :type_class, :read_only, :alias, :default, :casted, :init_method, :options
7
+ attr_reader :name, :type, :type_class, :read_only, :alias, :default, :casted, :init_method, :options, :allow_blank
8
8
 
9
9
  # Attribute to define.
10
10
  # All Properties are assumed casted unless the type is nil.
@@ -33,6 +33,7 @@ module CouchRest::Model
33
33
  raise "Expecting an array or keyed hash for property #{parent.class.name}##{self.name}"
34
34
  end
35
35
  arr = value.collect { |data| cast_value(parent, data) }
36
+ arr.reject!{ |data| data.nil? } unless allow_blank
36
37
  # allow casted_by calls to be passed up chain by wrapping in CastedArray
37
38
  CastedArray.new(arr, self, parent)
38
39
  elsif (type == Object || type == Hash) && (value.is_a?(Hash))
@@ -45,8 +46,12 @@ module CouchRest::Model
45
46
 
46
47
  # Cast an individual value
47
48
  def cast_value(parent, value)
48
- value = typecast_value(value, self)
49
- associate_casted_value_to_parent(parent, value)
49
+ if !allow_blank && value.to_s.empty?
50
+ nil
51
+ else
52
+ value = typecast_value(parent, self, value)
53
+ associate_casted_value_to_parent(parent, value)
54
+ end
50
55
  end
51
56
 
52
57
  def default_value
@@ -64,6 +69,7 @@ module CouchRest::Model
64
69
  # a normal call to the class.
65
70
  def build(*args)
66
71
  raise StandardError, "Cannot build property without a class" if @type_class.nil?
72
+
67
73
  if @init_method.is_a?(Proc)
68
74
  @init_method.call(*args)
69
75
  else
@@ -102,13 +108,13 @@ module CouchRest::Model
102
108
  end
103
109
 
104
110
  def parse_options(options)
105
- @validation_format = options.delete(:format) if options[:format]
106
- @read_only = options.delete(:read_only) if options[:read_only]
107
- @alias = options.delete(:alias) if options[:alias]
108
- @default = options.delete(:default) unless options[:default].nil?
109
- @init_method = options[:init_method] ? options.delete(:init_method) : 'new'
111
+ @validation_format = options.delete(:format) if options[:format]
112
+ @read_only = options.delete(:read_only) if options[:read_only]
113
+ @alias = options.delete(:alias) if options[:alias]
114
+ @default = options.delete(:default) unless options[:default].nil?
115
+ @init_method = options.delete(:init_method) || 'new'
116
+ @allow_blank = options[:allow_blank].nil? ? true : options.delete(:allow_blank)
110
117
  @options = options
111
118
  end
112
-
113
119
  end
114
120
  end
@@ -2,7 +2,7 @@ module CouchRest
2
2
  module Model
3
3
  module Typecast
4
4
 
5
- def typecast_value(value, property) # klass, init_method)
5
+ def typecast_value(parent, property, value)
6
6
  return nil if value.nil?
7
7
  klass = property.type_class
8
8
  if value.instance_of?(klass) || klass == Object
@@ -11,6 +11,8 @@ module CouchRest
11
11
  else
12
12
  value
13
13
  end
14
+ elsif klass.respond_to?(:couchrest_typecast)
15
+ klass.couchrest_typecast(parent, property, value)
14
16
  elsif [String, TrueClass, Integer, Float, BigDecimal, DateTime, Time, Date, Class].include?(klass)
15
17
  send('typecast_to_'+klass.to_s.downcase, value)
16
18
  else
@@ -1,10 +1,12 @@
1
1
  require 'question'
2
2
  require 'person'
3
+ require 'money'
3
4
 
4
5
  class Course < CouchRest::Model::Base
5
6
  use_database TEST_SERVER.default_database
6
7
 
7
8
  property :title, String
9
+ property :subtitle, String, :allow_blank => false
8
10
  property :questions, [Question]
9
11
  property :professor, Person
10
12
  property :participants, [Object]
@@ -17,6 +19,8 @@ class Course < CouchRest::Model::Base
17
19
  property :active, :type => TrueClass
18
20
  property :very_active, :type => TrueClass
19
21
  property :klass, :type => Class
22
+ property :currency, String, :default => 'EUR'
23
+ property :price, Money
20
24
 
21
25
  design do
22
26
  view :by_title
@@ -0,0 +1,24 @@
1
+
2
+ # Really simple money class for testing
3
+ class Money
4
+
5
+ attr_accessor :cents, :currency
6
+
7
+ def initialize(cents, currency = nil)
8
+ self.cents = cents.to_i
9
+ self.currency = currency
10
+ end
11
+
12
+ def to_s
13
+ (self.cents.to_f / 100).to_s
14
+ end
15
+
16
+ def self.couchrest_typecast(parent, property, value)
17
+ if parent.respond_to?(:currency)
18
+ new(value, parent.currency)
19
+ else
20
+ new(value)
21
+ end
22
+ end
23
+
24
+ end
@@ -70,6 +70,11 @@ describe "Assocations" do
70
70
  @invoice.client
71
71
  end
72
72
 
73
+ it "should ignore blank ids" do
74
+ @invoice.client_id = ""
75
+ @invoice.client_id.should be_nil
76
+ end
77
+
73
78
  it "should allow override of foreign key" do
74
79
  @invoice.respond_to?(:alternate_client).should be_true
75
80
  @invoice.respond_to?("alternate_client=").should be_true
@@ -116,6 +121,11 @@ describe "Assocations" do
116
121
  @invoice.entries.first.should eql(@entries.first)
117
122
  end
118
123
 
124
+ it "should ignore blank ids when set directly" do
125
+ @invoice.entry_ids = ["", @entries.first.id]
126
+ @invoice.entry_ids.length.should be(1)
127
+ end
128
+
119
129
  it "should replace collection if ids replaced" do
120
130
  @invoice.entry_ids = @entries.collect{|i| i.id}
121
131
  @invoice.entries.length.should eql(3) # load once
@@ -560,24 +560,6 @@ describe "Model Base" do
560
560
  'index' => "function(doc) { ret = new Document(); ret.add(doc['name'], {'field':'name'}); return ret; }" }
561
561
  @db.save_doc({'_id' => '_design/search', 'fulltext' => {'cats' => search_function}})
562
562
  end
563
-
564
- it "should be able to paginate through a large set of search results" do
565
- if couchdb_lucene_available?
566
- names = []
567
- Cat.paginated_each(:design_doc => "search", :view_name => "cats",
568
- :q => 'name:S*', :search => true, :include_docs => true, :per_page => 3) do |cat|
569
- cat.should_not be_nil
570
- names << cat.name
571
- end
572
-
573
- names.size.should == 5
574
- names.should include('Sockington')
575
- names.should include('Smitty')
576
- names.should include('Sammy')
577
- names.should include('Samson')
578
- names.should include('Simon')
579
- end
580
- end
581
563
  end
582
564
 
583
565
  end
@@ -33,11 +33,26 @@ describe "Dirty" do
33
33
 
34
34
  describe "changes" do
35
35
 
36
- it "should return changes on an attribute" do
37
- @card = Card.new(:first_name => "matt")
38
- @card.first_name = "andrew"
39
- @card.first_name_changed?.should be_true
40
- @card.changes.should == { "first_name" => ["matt", "andrew"] }
36
+ context "when new record" do
37
+ it "should return changes on an attribute" do
38
+ @card = Card.new(:first_name => "matt")
39
+ @card.first_name = "andrew"
40
+ @card.first_name_changed?.should be_true
41
+ if ActiveModel::VERSION::STRING > "3.2.0"
42
+ @card.changes.should == { "first_name" => [nil, "andrew"] }
43
+ else
44
+ @card.changes.should == { "first_name" => ["matt", "andrew"] }
45
+ end
46
+ end
47
+ end
48
+
49
+ context "when persisted" do
50
+ it "should return changes on an attribute" do
51
+ @card = Card.create!(:first_name => "matt")
52
+ @card.first_name = "andrew"
53
+ @card.first_name_changed?.should be_true
54
+ @card.changes.should == { "first_name" => ["matt", "andrew"] }
55
+ end
41
56
  end
42
57
 
43
58
  end
@@ -328,7 +328,6 @@ describe "properties of array of casted models" do
328
328
  @course.questions.last.class.should eql(Question)
329
329
  end
330
330
 
331
-
332
331
  it "should raise an error if attempting to set single value for array type" do
333
332
  lambda {
334
333
  @course.questions = Question.new(:q => 'test1')
@@ -428,6 +427,16 @@ describe "Property Class" do
428
427
  property.init_method.should eql('parse')
429
428
  end
430
429
 
430
+ it "should set the allow_blank option to true by default" do
431
+ property = CouchRest::Model::Property.new(:test, String)
432
+ property.allow_blank.should be_true
433
+ end
434
+
435
+ it "should allow setting of the allow_blank option to false" do
436
+ property = CouchRest::Model::Property.new(:test, String, :allow_blank => false)
437
+ property.allow_blank.should be_false
438
+ end
439
+
431
440
  describe "#build" do
432
441
  it "should allow instantiation of new object" do
433
442
  property = CouchRest::Model::Property.new(:test, Date)
@@ -466,6 +475,22 @@ describe "Property Class" do
466
475
  property.cast(parent, ["2010-06-01", "2010-06-02"]).should eql([Date.new(2010, 6, 1), Date.new(2010, 6, 2)])
467
476
  end
468
477
 
478
+ context "when allow_blank is false" do
479
+ let :parent do
480
+ mock("FooObject")
481
+ end
482
+
483
+ it "should convert blank to nil" do
484
+ property = CouchRest::Model::Property.new(:test, String, :allow_blank => false)
485
+ property.cast(parent, "").should be_nil
486
+ end
487
+
488
+ it "should remove blank array entries" do
489
+ property = CouchRest::Model::Property.new(:test, [String], :allow_blank => false)
490
+ property.cast(parent, ["", "foo"]).should eql(["foo"])
491
+ end
492
+ end
493
+
469
494
  it "should set a CastedArray on array of Objects" do
470
495
  property = CouchRest::Model::Property.new(:test, [Object])
471
496
  parent = mock("FooObject")
@@ -14,6 +14,28 @@ describe "Type Casting" do
14
14
  end
15
15
  end
16
16
 
17
+ describe "when value is empty string" do
18
+ it "leaves the value unchanged" do
19
+ @course.title = ""
20
+ @course['title'].should == ""
21
+ end
22
+ end
23
+
24
+ describe "when blank is not allow on property" do
25
+ it "leaves nil as nil" do
26
+ @course.subtitle = nil
27
+ @course['subtitle'].should == nil
28
+ end
29
+ it "converts blank to nil" do
30
+ @course.subtitle = ""
31
+ @course['subtitle'].should == nil
32
+ end
33
+ it "leaves text as text" do
34
+ @course.subtitle = "Test"
35
+ @course['subtitle'].should == "Test"
36
+ end
37
+ end
38
+
17
39
  describe "when type primitive is an Object" do
18
40
  it "it should not cast given value" do
19
41
  @course.participants = [{}, 'q', 1]
@@ -26,6 +48,14 @@ describe "Type Casting" do
26
48
  end
27
49
  end
28
50
 
51
+ describe "when class responds to .couchrest_typecast" do
52
+ it "should accept call" do
53
+ @course.price = "1299"
54
+ @course.price.cents.should eql(1299)
55
+ @course.price.currency.should eql('EUR')
56
+ end
57
+ end
58
+
29
59
  describe "when type primitive is a String" do
30
60
  it "keeps string value unchanged" do
31
61
  value = "1.0"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: couchrest_model
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.beta
4
+ version: 2.0.0.beta2
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2012-06-14 00:00:00.000000000 Z
16
+ date: 2012-08-02 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: couchrest
@@ -22,7 +22,7 @@ dependencies:
22
22
  requirements:
23
23
  - - ~>
24
24
  - !ruby/object:Gem::Version
25
- version: 1.1.2
25
+ version: 1.1.3
26
26
  type: :runtime
27
27
  prerelease: false
28
28
  version_requirements: !ruby/object:Gem::Requirement
@@ -30,7 +30,7 @@ dependencies:
30
30
  requirements:
31
31
  - - ~>
32
32
  - !ruby/object:Gem::Version
33
- version: 1.1.2
33
+ version: 1.1.3
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: mime-types
36
36
  requirement: !ruby/object:Gem::Requirement
@@ -54,7 +54,7 @@ dependencies:
54
54
  requirements:
55
55
  - - ~>
56
56
  - !ruby/object:Gem::Version
57
- version: 3.1.0
57
+ version: '3.0'
58
58
  type: :runtime
59
59
  prerelease: false
60
60
  version_requirements: !ruby/object:Gem::Requirement
@@ -62,7 +62,7 @@ dependencies:
62
62
  requirements:
63
63
  - - ~>
64
64
  - !ruby/object:Gem::Version
65
- version: 3.1.0
65
+ version: '3.0'
66
66
  - !ruby/object:Gem::Dependency
67
67
  name: tzinfo
68
68
  requirement: !ruby/object:Gem::Requirement
@@ -143,6 +143,22 @@ dependencies:
143
143
  - - ! '>='
144
144
  - !ruby/object:Gem::Version
145
145
  version: 0.8.0
146
+ - !ruby/object:Gem::Dependency
147
+ name: debugger
148
+ requirement: !ruby/object:Gem::Requirement
149
+ none: false
150
+ requirements:
151
+ - - ~>
152
+ - !ruby/object:Gem::Version
153
+ version: 1.2.0
154
+ type: :development
155
+ prerelease: false
156
+ version_requirements: !ruby/object:Gem::Requirement
157
+ none: false
158
+ requirements:
159
+ - - ~>
160
+ - !ruby/object:Gem::Version
161
+ version: 1.2.0
146
162
  description: CouchRest Model provides aditional features to the standard CouchRest
147
163
  Document class such as properties, view designs, associations, callbacks, typecasting
148
164
  and validations.
@@ -220,6 +236,7 @@ files:
220
236
  - spec/fixtures/models/invoice.rb
221
237
  - spec/fixtures/models/key_chain.rb
222
238
  - spec/fixtures/models/membership.rb
239
+ - spec/fixtures/models/money.rb
223
240
  - spec/fixtures/models/person.rb
224
241
  - spec/fixtures/models/project.rb
225
242
  - spec/fixtures/models/question.rb
@@ -267,6 +284,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
267
284
  - - ! '>='
268
285
  - !ruby/object:Gem::Version
269
286
  version: '0'
287
+ segments:
288
+ - 0
289
+ hash: 2665370531854453498
270
290
  required_rubygems_version: !ruby/object:Gem::Requirement
271
291
  none: false
272
292
  requirements:
@@ -294,6 +314,7 @@ test_files:
294
314
  - spec/fixtures/models/invoice.rb
295
315
  - spec/fixtures/models/key_chain.rb
296
316
  - spec/fixtures/models/membership.rb
317
+ - spec/fixtures/models/money.rb
297
318
  - spec/fixtures/models/person.rb
298
319
  - spec/fixtures/models/project.rb
299
320
  - spec/fixtures/models/question.rb