couchrest_extended_document 1.0.0.beta6 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -100,7 +100,7 @@ module CouchRest
100
100
  end
101
101
 
102
102
  # length
103
- if property.type == String
103
+ if property.type_class == String
104
104
  # XXX: maybe length should always return a Range, with the min defaulting to 1
105
105
  # 52 being the max set
106
106
  len = property.options.fetch(:length, property.options.fetch(:size, 52))
@@ -137,16 +137,16 @@ module CouchRest
137
137
  end
138
138
 
139
139
  # numeric validator
140
- if "Integer" == property.type
140
+ if property.type_class == Integer
141
141
  opts[:integer_only] = true
142
142
  validates_numericality_of property.name, options_with_message(opts, property, :is_number)
143
- elsif Float == property.type
143
+ elsif Float == property.type_class
144
144
  opts[:precision] = property.precision
145
145
  opts[:scale] = property.scale
146
146
  validates_numericality_of property.name, options_with_message(opts, property, :is_number)
147
147
  end
148
148
 
149
- # marked the property has checked
149
+ # marked the property as checked
150
150
  property.autovalidation_check = true
151
151
 
152
152
  end
@@ -5,6 +5,7 @@ gem "builder", ">=2.1.2"
5
5
 
6
6
  gem 'activesupport', ">= 2.3.0"
7
7
  require 'active_support/core_ext'
8
+ require 'active_support/json'
8
9
 
9
10
  gem "mime-types", ">= 1.15"
10
11
  require 'mime/types'
@@ -19,8 +19,11 @@ end
19
19
  class DummyModel < CouchRest::ExtendedDocument
20
20
  use_database TEST_SERVER.default_database
21
21
  raise "Default DB not set" if TEST_SERVER.default_database.nil?
22
- property :casted_attribute, :cast_as => 'WithCastedModelMixin'
23
- property :keywords, :cast_as => ["String"]
22
+ property :casted_attribute, WithCastedModelMixin
23
+ property :keywords, ["String"]
24
+ property :sub_models do |child|
25
+ child.property :title
26
+ end
24
27
  end
25
28
 
26
29
  class CastedCallbackDoc < CouchRest::ExtendedDocument
@@ -82,6 +85,20 @@ describe CouchRest::CastedModel do
82
85
  @casted_obj.should == nil
83
86
  end
84
87
  end
88
+
89
+ describe "anonymous sub casted models" do
90
+ before :each do
91
+ @obj = DummyModel.new
92
+ end
93
+ it "should be empty initially" do
94
+ @obj.sub_models.should_not be_nil
95
+ @obj.sub_models.should be_empty
96
+ end
97
+ it "should be updatable using a hash" do
98
+ @obj.sub_models << {:title => 'test'}
99
+ @obj.sub_models.first.title.should eql('test')
100
+ end
101
+ end
85
102
 
86
103
  describe "casted as attribute" do
87
104
  before(:each) do
@@ -308,6 +325,7 @@ describe CouchRest::CastedModel do
308
325
  @cat.create
309
326
  @cat.save
310
327
  @cat.favorite_toy.should_not be_new
328
+ @cat.toys.first.casted_by.should eql(@cat)
311
329
  @cat.toys.first.should_not be_new
312
330
  end
313
331
 
@@ -226,18 +226,19 @@ describe "ExtendedDocument" do
226
226
  @art['title'].should == "something else"
227
227
  end
228
228
 
229
- it "should flip out if an attribute= method is missing" do
229
+ it "should not flip out if an attribute= method is missing and ignore it" do
230
230
  lambda {
231
- @art.update_attributes_without_saving('slug' => "new-slug", :title => "super danger")
232
- }.should raise_error
231
+ @art.update_attributes_without_saving('slug' => "new-slug", :title => "super danger")
232
+ }.should_not raise_error
233
+ @art.slug.should == "big-bad-danger"
233
234
  end
234
235
 
235
- it "should not change other attributes if there is an error" do
236
- lambda {
237
- @art.update_attributes_without_saving('slug' => "new-slug", :title => "super danger")
238
- }.should raise_error
239
- @art['title'].should == "big bad danger"
240
- end
236
+ #it "should not change other attributes if there is an error" do
237
+ # lambda {
238
+ # @art.update_attributes_without_saving('slug' => "new-slug", :title => "super danger")
239
+ # }.should raise_error
240
+ # @art['title'].should == "big bad danger"
241
+ #end
241
242
  end
242
243
 
243
244
  describe "update attributes" do
@@ -57,7 +57,45 @@ describe "ExtendedDocument properties" do
57
57
  @card.created_at.should_not be_nil
58
58
  @card.updated_at.should_not be_nil
59
59
  end
60
-
60
+
61
+ it "should let you use read_attribute method" do
62
+ @card.last_name = "Aimonetti"
63
+ @card.read_attribute(:last_name).should eql('Aimonetti')
64
+ @card.read_attribute('last_name').should eql('Aimonetti')
65
+ last_name_prop = @card.properties.find{|p| p.name == 'last_name'}
66
+ @card.read_attribute(last_name_prop).should eql('Aimonetti')
67
+ end
68
+
69
+ it "should let you use write_attribute method" do
70
+ @card.write_attribute(:last_name, 'Aimonetti 1')
71
+ @card.last_name.should eql('Aimonetti 1')
72
+ @card.write_attribute('last_name', 'Aimonetti 2')
73
+ @card.last_name.should eql('Aimonetti 2')
74
+ last_name_prop = @card.properties.find{|p| p.name == 'last_name'}
75
+ @card.write_attribute(last_name_prop, 'Aimonetti 3')
76
+ @card.last_name.should eql('Aimonetti 3')
77
+ end
78
+
79
+ it "should let you use write_attribute on readonly properties" do
80
+ lambda {
81
+ @card.read_only_value = "foo"
82
+ }.should raise_error
83
+ @card.write_attribute(:read_only_value, "foo")
84
+ @card.read_only_value.should == 'foo'
85
+ end
86
+
87
+ it "should cast via write_attribute" do
88
+ @card.write_attribute(:cast_alias, {:name => ["Sam", "Lown"]})
89
+ @card.cast_alias.class.should eql(Person)
90
+ @card.cast_alias.name.last.should eql("Lown")
91
+ end
92
+
93
+ it "should not cast via write_attribute if property not casted" do
94
+ @card.write_attribute(:first_name, {:name => "Sam"})
95
+ @card.first_name.class.should eql(Hash)
96
+ @card.first_name[:name].should eql("Sam")
97
+ end
98
+
61
99
 
62
100
  describe "mass assignment protection" do
63
101
 
@@ -646,3 +684,107 @@ describe "a casted model retrieved from the database" do
646
684
  end
647
685
  end
648
686
  end
687
+
688
+ describe "Property Class" do
689
+
690
+ it "should provide name as string" do
691
+ property = CouchRest::Property.new(:test, String)
692
+ property.name.should eql('test')
693
+ property.to_s.should eql('test')
694
+ end
695
+
696
+ it "should provide class from type" do
697
+ property = CouchRest::Property.new(:test, String)
698
+ property.type_class.should eql(String)
699
+ end
700
+
701
+ it "should provide base class from type in array" do
702
+ property = CouchRest::Property.new(:test, [String])
703
+ property.type_class.should eql(String)
704
+ end
705
+
706
+ it "should leave type as string if requested" do
707
+ property = CouchRest::Property.new(:test, 'String')
708
+ property.type.should eql('String')
709
+ property.type_class.should eql(String)
710
+ end
711
+
712
+ it "should leave type nil and return string by default" do
713
+ property = CouchRest::Property.new(:test, nil)
714
+ property.type.should be_nil
715
+ # Type cast should never be used on non-casted property!
716
+ property.type_class.should eql(String)
717
+ end
718
+
719
+ it "should convert empty type array to [String]" do
720
+ property = CouchRest::Property.new(:test, [])
721
+ property.type_class.should eql(String)
722
+ end
723
+
724
+ it "should convert boolean text-type TrueClass" do
725
+ property = CouchRest::Property.new(:test, 'boolean')
726
+ property.type.should eql('boolean') # no change
727
+ property.type_class.should eql(TrueClass)
728
+ end
729
+
730
+ it "should set init method option or leave as 'new'" do
731
+ # (bad example! Time already typecast)
732
+ property = CouchRest::Property.new(:test, Time)
733
+ property.init_method.should eql('new')
734
+ property = CouchRest::Property.new(:test, Time, :init_method => 'parse')
735
+ property.init_method.should eql('parse')
736
+ end
737
+
738
+ ## Property Casting method. More thoroughly tested earlier.
739
+
740
+ describe "casting" do
741
+ it "should cast a value" do
742
+ property = CouchRest::Property.new(:test, Date)
743
+ parent = mock("FooObject")
744
+ property.cast(parent, "2010-06-16").should eql(Date.new(2010, 6, 16))
745
+ property.cast_value(parent, "2010-06-16").should eql(Date.new(2010, 6, 16))
746
+ end
747
+
748
+ it "should cast an array of values" do
749
+ property = CouchRest::Property.new(:test, [Date])
750
+ parent = mock("FooObject")
751
+ property.cast(parent, ["2010-06-01", "2010-06-02"]).should eql([Date.new(2010, 6, 1), Date.new(2010, 6, 2)])
752
+ end
753
+
754
+ it "should set a CastedArray on array of Objects" do
755
+ property = CouchRest::Property.new(:test, [Object])
756
+ parent = mock("FooObject")
757
+ property.cast(parent, ["2010-06-01", "2010-06-02"]).class.should eql(::CouchRest::CastedArray)
758
+ end
759
+
760
+ it "should not set a CastedArray on array of Strings" do
761
+ property = CouchRest::Property.new(:test, [String])
762
+ parent = mock("FooObject")
763
+ property.cast(parent, ["2010-06-01", "2010-06-02"]).class.should_not eql(::CouchRest::CastedArray)
764
+ end
765
+
766
+ it "should raise and error if value is array when type is not" do
767
+ property = CouchRest::Property.new(:test, Date)
768
+ parent = mock("FooClass")
769
+ lambda {
770
+ cast = property.cast(parent, [Date.new(2010, 6, 1)])
771
+ }.should raise_error
772
+ end
773
+
774
+
775
+ it "should set parent as casted_by object in CastedArray" do
776
+ property = CouchRest::Property.new(:test, [Object])
777
+ parent = mock("FooObject")
778
+ property.cast(parent, ["2010-06-01", "2010-06-02"]).casted_by.should eql(parent)
779
+ end
780
+
781
+ it "should set casted_by on new value" do
782
+ property = CouchRest::Property.new(:test, CatToy)
783
+ parent = mock("CatObject")
784
+ cast = property.cast(parent, {:name => 'catnip'})
785
+ cast.casted_by.should eql(parent)
786
+ end
787
+
788
+ end
789
+
790
+ end
@@ -11,7 +11,7 @@ class Card < CouchRest::ExtendedDocument
11
11
  property :first_name
12
12
  property :last_name, :alias => :family_name
13
13
  property :read_only_value, :read_only => true
14
- property :cast_alias, :cast_as => Person, :alias => :calias
14
+ property :cast_alias, Person, :alias => :calias
15
15
 
16
16
 
17
17
  timestamps!
@@ -2,5 +2,6 @@ class Question < Hash
2
2
  include ::CouchRest::CastedModel
3
3
 
4
4
  property :q
5
- property :a, :type => 'Object'
6
- end
5
+ property :a
6
+
7
+ end
metadata CHANGED
@@ -1,25 +1,25 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: couchrest_extended_document
3
3
  version: !ruby/object:Gem::Version
4
- hash: -1848230058
5
- prerelease: true
4
+ hash: 23
5
+ prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
9
  - 0
10
- - beta6
11
- version: 1.0.0.beta6
10
+ version: 1.0.0
12
11
  platform: ruby
13
12
  authors:
14
13
  - J. Chris Anderson
15
14
  - Matt Aimonetti
16
15
  - Marcos Tapajos
17
16
  - Will Leinweber
17
+ - Sam Lown
18
18
  autorequire:
19
19
  bindir: bin
20
20
  cert_chain: []
21
21
 
22
- date: 2010-07-01 00:00:00 -03:00
22
+ date: 2010-08-01 00:00:00 -03:00
23
23
  default_executable:
24
24
  dependencies:
25
25
  - !ruby/object:Gem::Dependency
@@ -30,13 +30,12 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- hash: 31098193
33
+ hash: 23
34
34
  segments:
35
35
  - 1
36
36
  - 0
37
37
  - 0
38
- - beta
39
- version: 1.0.0.beta
38
+ version: 1.0.0
40
39
  type: :runtime
41
40
  version_requirements: *id001
42
41
  - !ruby/object:Gem::Dependency
@@ -108,6 +107,7 @@ files:
108
107
  - lib/couchrest/extended_document.rb
109
108
  - lib/couchrest/mixins.rb
110
109
  - lib/couchrest/mixins/attribute_protection.rb
110
+ - lib/couchrest/mixins/attributes.rb
111
111
  - lib/couchrest/mixins/callbacks.rb
112
112
  - lib/couchrest/mixins/class_proxy.rb
113
113
  - lib/couchrest/mixins/collection.rb
@@ -115,12 +115,11 @@ files:
115
115
  - lib/couchrest/mixins/document_queries.rb
116
116
  - lib/couchrest/mixins/extended_attachments.rb
117
117
  - lib/couchrest/mixins/properties.rb
118
- - lib/couchrest/mixins/validation.rb
118
+ - lib/couchrest/mixins/typecast.rb
119
119
  - lib/couchrest/mixins/views.rb
120
120
  - lib/couchrest/property.rb
121
121
  - lib/couchrest/support/couchrest.rb
122
122
  - lib/couchrest/support/rails.rb
123
- - lib/couchrest/typecast.rb
124
123
  - lib/couchrest/validation.rb
125
124
  - lib/couchrest/validation/auto_validate.rb
126
125
  - lib/couchrest/validation/contextual_validators.rb
@@ -188,14 +187,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
188
187
  required_rubygems_version: !ruby/object:Gem::Requirement
189
188
  none: false
190
189
  requirements:
191
- - - ">"
190
+ - - ">="
192
191
  - !ruby/object:Gem::Version
193
- hash: 25
192
+ hash: 3
194
193
  segments:
195
- - 1
196
- - 3
197
- - 1
198
- version: 1.3.1
194
+ - 0
195
+ version: "0"
199
196
  requirements: []
200
197
 
201
198
  rubyforge_project:
@@ -1,245 +0,0 @@
1
- # Extracted from dm-validations 0.9.10
2
- #
3
- # Copyright (c) 2007 Guy van den Berg
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining
6
- # a copy of this software and associated documentation files (the
7
- # "Software"), to deal in the Software without restriction, including
8
- # without limitation the rights to use, copy, modify, merge, publish,
9
- # distribute, sublicense, and/or sell copies of the Software, and to
10
- # permit persons to whom the Software is furnished to do so, subject to
11
- # the following conditions:
12
- #
13
- # The above copyright notice and this permission notice shall be
14
- # included in all copies or substantial portions of the Software.
15
- #
16
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
-
24
- class Object
25
- def validatable?
26
- false
27
- end
28
- end
29
-
30
- require 'pathname'
31
-
32
- dir = File.join(Pathname(__FILE__).dirname.expand_path, '..', 'validation')
33
-
34
- require File.join(dir, 'validation_errors')
35
- require File.join(dir, 'contextual_validators')
36
- require File.join(dir, 'auto_validate')
37
-
38
- require File.join(dir, 'validators', 'generic_validator')
39
- require File.join(dir, 'validators', 'required_field_validator')
40
- require File.join(dir, 'validators', 'absent_field_validator')
41
- require File.join(dir, 'validators', 'format_validator')
42
- require File.join(dir, 'validators', 'length_validator')
43
- require File.join(dir, 'validators', 'numeric_validator')
44
- require File.join(dir, 'validators', 'method_validator')
45
- require File.join(dir, 'validators', 'confirmation_validator')
46
-
47
- module CouchRest
48
- module Validation
49
-
50
- def self.included(base)
51
- base.extlib_inheritable_accessor(:auto_validation)
52
- base.class_eval <<-EOS, __FILE__, __LINE__ + 1
53
- # Callbacks
54
- define_callbacks :validate
55
-
56
- # Turn off auto validation by default
57
- self.auto_validation ||= false
58
-
59
- # Force the auto validation for the class properties
60
- # This feature is still not fully ported over,
61
- # test are lacking, so please use with caution
62
- def self.auto_validate!
63
- self.auto_validation = true
64
- end
65
-
66
- # share the validations with subclasses
67
- def self.inherited(subklass)
68
- self.validators.contexts.each do |k, v|
69
- subklass.validators.contexts[k] = v.dup
70
- end
71
- super
72
- end
73
- EOS
74
-
75
- base.extend(ClassMethods)
76
- base.class_eval <<-EOS, __FILE__, __LINE__ + 1
77
- define_callbacks :validate
78
- if method_defined?(:_run_save_callbacks)
79
- set_callback :save, :before, :check_validations
80
- end
81
- EOS
82
- base.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
83
- def self.define_property(name, options={})
84
- super
85
- auto_generate_validations(properties.last) if properties && properties.size > 0
86
- autovalidation_check = true
87
- end
88
- RUBY_EVAL
89
- end
90
-
91
- # Ensures the object is valid for the context provided, and otherwise
92
- # throws :halt and returns false.
93
- #
94
- def check_validations(context = :default)
95
- throw(:halt, false) unless context.nil? || valid?(context)
96
- end
97
-
98
- # Return the ValidationErrors
99
- #
100
- def errors
101
- @errors ||= ValidationErrors.new
102
- end
103
-
104
- # Mark this resource as validatable. When we validate associations of a
105
- # resource we can check if they respond to validatable? before trying to
106
- # recursivly validate them
107
- #
108
- def validatable?
109
- true
110
- end
111
-
112
- # Alias for valid?(:default)
113
- #
114
- def valid_for_default?
115
- valid?(:default)
116
- end
117
-
118
- # Check if a resource is valid in a given context
119
- #
120
- def valid?(context = :default)
121
- recursive_valid?(self, context, true)
122
- end
123
-
124
- # checking on casted objects
125
- def validate_casted_arrays
126
- result = true
127
- array_casted_properties = self.class.properties.select { |property| property.casted && property.type.instance_of?(Array) }
128
- array_casted_properties.each do |property|
129
- casted_values = self.send(property.name)
130
- next unless casted_values.is_a?(Array) && casted_values.first.respond_to?(:valid?)
131
- casted_values.each do |value|
132
- result = (result && value.valid?) if value.respond_to?(:valid?)
133
- end
134
- end
135
- result
136
- end
137
-
138
- # Do recursive validity checking
139
- #
140
- def recursive_valid?(target, context, state)
141
- valid = state
142
- target.each do |key, prop|
143
- if prop.is_a?(Array)
144
- prop.each do |item|
145
- if item.validatable?
146
- valid = recursive_valid?(item, context, valid) && valid
147
- end
148
- end
149
- elsif prop.validatable?
150
- valid = recursive_valid?(prop, context, valid) && valid
151
- end
152
- end
153
- target._run_validate_callbacks do
154
- target.class.validators.execute(context, target) && valid
155
- end
156
- end
157
-
158
-
159
- def validation_property_value(name)
160
- self.respond_to?(name, true) ? self.send(name) : nil
161
- end
162
-
163
- # Get the corresponding Object property, if it exists.
164
- def validation_property(field_name)
165
- properties.find{|p| p.name == field_name}
166
- end
167
-
168
- module ClassMethods
169
- include CouchRest::Validation::ValidatesPresent
170
- include CouchRest::Validation::ValidatesAbsent
171
- include CouchRest::Validation::ValidatesIsConfirmed
172
- # include CouchRest::Validation::ValidatesIsPrimitive
173
- # include CouchRest::Validation::ValidatesIsAccepted
174
- include CouchRest::Validation::ValidatesFormat
175
- include CouchRest::Validation::ValidatesLength
176
- # include CouchRest::Validation::ValidatesWithin
177
- include CouchRest::Validation::ValidatesIsNumber
178
- include CouchRest::Validation::ValidatesWithMethod
179
- # include CouchRest::Validation::ValidatesWithBlock
180
- # include CouchRest::Validation::ValidatesIsUnique
181
- include CouchRest::Validation::AutoValidate
182
-
183
- # Return the set of contextual validators or create a new one
184
- #
185
- def validators
186
- @validations ||= ContextualValidators.new
187
- end
188
-
189
- # Clean up the argument list and return a opts hash, including the
190
- # merging of any default opts. Set the context to default if none is
191
- # provided. Also allow :context to be aliased to :on, :when & group
192
- #
193
- def opts_from_validator_args(args, defaults = nil)
194
- opts = args.last.kind_of?(Hash) ? args.pop : {}
195
- context = :default
196
- context = opts[:context] if opts.has_key?(:context)
197
- context = opts.delete(:on) if opts.has_key?(:on)
198
- context = opts.delete(:when) if opts.has_key?(:when)
199
- context = opts.delete(:group) if opts.has_key?(:group)
200
- opts[:context] = context
201
- opts.merge!(defaults) unless defaults.nil?
202
- opts
203
- end
204
-
205
- # Given a new context create an instance method of
206
- # valid_for_<context>? which simply calls valid?(context)
207
- # if it does not already exist
208
- #
209
- def create_context_instance_methods(context)
210
- name = "valid_for_#{context.to_s}?" # valid_for_signup?
211
- if !self.instance_methods.include?(name)
212
- class_eval <<-EOS, __FILE__, __LINE__ + 1
213
- def #{name} # def valid_for_signup?
214
- valid?('#{context.to_s}'.to_sym) # valid?('signup'.to_sym)
215
- end # end
216
- EOS
217
- end
218
- end
219
-
220
- # Create a new validator of the given klazz and push it onto the
221
- # requested context for each of the attributes in the fields list
222
- #
223
- def add_validator_to_context(opts, fields, klazz)
224
- fields.each do |field|
225
- validator = klazz.new(field.to_sym, opts)
226
- if opts[:context].is_a?(Symbol)
227
- unless validators.context(opts[:context]).include?(validator)
228
- validators.context(opts[:context]) << validator
229
- create_context_instance_methods(opts[:context])
230
- end
231
- elsif opts[:context].is_a?(Array)
232
- opts[:context].each do |c|
233
- unless validators.context(c).include?(validator)
234
- validators.context(c) << validator
235
- create_context_instance_methods(c)
236
- end
237
- end
238
- end
239
- end
240
- end
241
-
242
- end # module ClassMethods
243
- end # module Validation
244
-
245
- end # module CouchRest