davber_couch_potato 0.3.0 → 0.4.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/CHANGES.md +18 -1
- data/README.md +35 -6
- data/VERSION.yml +1 -1
- data/lib/core_ext/date.rb +3 -10
- data/lib/core_ext/string.rb +5 -1
- data/lib/core_ext/time.rb +3 -9
- data/lib/couch_potato/database.rb +31 -27
- data/lib/couch_potato/persistence.rb +24 -5
- data/lib/couch_potato/persistence/callbacks.rb +11 -44
- data/lib/couch_potato/persistence/dirty_attributes.rb +18 -17
- data/lib/couch_potato/persistence/ghost_attributes.rb +14 -9
- data/lib/couch_potato/persistence/json.rb +3 -0
- data/lib/couch_potato/persistence/magic_timestamps.rb +4 -3
- data/lib/couch_potato/persistence/properties.rb +0 -7
- data/lib/couch_potato/persistence/simple_property.rb +3 -11
- data/lib/couch_potato/persistence/type_caster.rb +9 -9
- data/lib/couch_potato/railtie.rb +9 -3
- data/lib/couch_potato/validation/with_validatable.rb +10 -6
- data/lib/couch_potato/view/view_query.rb +19 -2
- data/rails/reload_classes.rb +1 -1
- data/spec/callbacks_spec.rb +2 -13
- data/spec/property_spec.rb +2 -2
- data/spec/rails_spec.rb +1 -2
- data/spec/railtie_spec.rb +63 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/unit/attributes_spec.rb +10 -0
- data/spec/unit/callbacks_spec.rb +3 -29
- data/spec/unit/database_spec.rb +2 -2
- data/spec/unit/date_spec.rb +2 -2
- data/spec/unit/dirty_attributes_spec.rb +7 -37
- data/spec/unit/initialize_spec.rb +38 -0
- data/spec/unit/time_spec.rb +2 -2
- metadata +26 -7
data/CHANGES.md
CHANGED
@@ -1,7 +1,24 @@
|
|
1
1
|
## Changes
|
2
2
|
|
3
|
-
### 0.
|
3
|
+
### 0.4.0
|
4
|
+
* ruby 1.9.2 compatibility (langalex)
|
5
|
+
* couch potato objects now behave correctly when used as keys in Hashes (langalex)
|
6
|
+
* use as\_json instead of to\_s(:json), which is the rails way
|
7
|
+
* use ActiveModel dirty tracking (langalex) - this means no more "deep tracking", e.g. `user.tags << 'new_tag'; user.dirty? # false`
|
8
|
+
|
9
|
+
### 0.3.2
|
10
|
+
* support yielding to blocks on #initialize (martinrehfeld)
|
11
|
+
* support for negative numbers in Fixnum/Float properties (langalex)
|
12
|
+
|
13
|
+
### 0.3.1
|
14
|
+
* ActiveModel callbacks (kazjote)
|
15
|
+
* do not use Rails.env in initializer as it will free Rails.env for all times and in Rails 2.3.x apps it will be called too early thus always beeing development (jweiss)
|
16
|
+
* ruby 1.9.2 compatibility (langalex)
|
17
|
+
* can configure validation framework in couchdb.yml, process couchdb.yml with erb (langalex)
|
18
|
+
|
19
|
+
### 0.3.0 - cloned gem!
|
4
20
|
* type field of documents now configurable, by using CouchPotato.type_field (davber)
|
21
|
+
* the mapping from class to design document name is now configurable, by using CouchPotato.design_name_fun, which is supposed to be a Proc (davber)
|
5
22
|
|
6
23
|
### 0.3.0
|
7
24
|
* support for lists (langalex)
|
data/README.md
CHANGED
@@ -22,6 +22,13 @@ Lastly Couch Potato aims to provide a seamless integration with Ruby on Rails, e
|
|
22
22
|
* declarative views with either custom or generated map/reduce functions
|
23
23
|
* extensive spec suite
|
24
24
|
|
25
|
+
### Supported Environments
|
26
|
+
|
27
|
+
* Ruby 1.8.7, 1.9.1, 1.9.2
|
28
|
+
* CouchDB 1.0.1
|
29
|
+
|
30
|
+
(Supported means I run the specs against those before releasing a new gem.)
|
31
|
+
|
25
32
|
### Installation
|
26
33
|
|
27
34
|
Couch Potato is hosted as a gem which you can install like this:
|
@@ -51,18 +58,40 @@ Optionally you can configure which framework you want to use for validations (ei
|
|
51
58
|
|
52
59
|
#### Using with Rails
|
53
60
|
|
54
|
-
|
61
|
+
Create a config/couchdb.yml:
|
62
|
+
|
63
|
+
default: &default
|
64
|
+
validation_framework: :active_model #optional
|
65
|
+
|
66
|
+
development:
|
67
|
+
<<: *default
|
68
|
+
database: development_db_name
|
69
|
+
test:
|
70
|
+
<<: *default
|
71
|
+
database: test_db_name
|
72
|
+
production:
|
73
|
+
<<: *default
|
74
|
+
database: <%= ENV['DB_NAME'] %>
|
75
|
+
|
76
|
+
#### Rails 2.x
|
77
|
+
|
78
|
+
Add to your _config/environment.rb_:
|
55
79
|
|
56
80
|
config.gem 'davber_couch_potato', :source => 'http://gemcutter.org'
|
57
81
|
config.frameworks -= [:active_record] # if you switch completely
|
82
|
+
|
83
|
+
#### Rails 3.x
|
58
84
|
|
59
|
-
|
85
|
+
Add to your _Gemfile_:
|
60
86
|
|
61
|
-
|
62
|
-
|
63
|
-
|
87
|
+
# gem 'rails' # we don't want to load activerecord so we can't require rails
|
88
|
+
gem 'railties'
|
89
|
+
gem 'actionpack'
|
90
|
+
gem 'actionmailer'
|
91
|
+
gem 'activemodel'
|
92
|
+
gem "couch_potato"
|
64
93
|
|
65
|
-
|
94
|
+
Note: please make sure that when you run `Date.today.as_json` in the Rails console it returns something like `2010/12/10` and not `2010-12-10` - if it does another gem has overwritten Couch Potato's Date patches - in this case move Couch Potato further down in your Gemfile or whereever you load it.
|
66
95
|
|
67
96
|
### Introduction
|
68
97
|
|
data/VERSION.yml
CHANGED
data/lib/core_ext/date.rb
CHANGED
@@ -1,18 +1,11 @@
|
|
1
1
|
class Date
|
2
2
|
def to_json(*a)
|
3
|
-
%("#{
|
3
|
+
%("#{as_json}")
|
4
4
|
end
|
5
5
|
|
6
|
-
def
|
7
|
-
|
8
|
-
strftime("%Y/%m/%d")
|
9
|
-
else
|
10
|
-
to_s_without_json *args
|
11
|
-
end
|
6
|
+
def as_json(*args)
|
7
|
+
strftime("%Y/%m/%d")
|
12
8
|
end
|
13
|
-
alias_method :to_s_without_json, :to_s
|
14
|
-
alias_method :to_s, :to_s_with_json
|
15
|
-
|
16
9
|
|
17
10
|
def self.json_create string
|
18
11
|
return nil if string.nil?
|
data/lib/core_ext/string.rb
CHANGED
@@ -4,5 +4,9 @@ module ActiveSupportMethods
|
|
4
4
|
$1.upcase
|
5
5
|
end
|
6
6
|
end
|
7
|
+
|
8
|
+
def blank?
|
9
|
+
empty?
|
10
|
+
end
|
7
11
|
end
|
8
|
-
String.send :include, ActiveSupportMethods unless String.new.respond_to?(:underscore)
|
12
|
+
String.send :include, ActiveSupportMethods unless String.new.respond_to?(:underscore)
|
data/lib/core_ext/time.rb
CHANGED
@@ -1,17 +1,11 @@
|
|
1
1
|
class Time
|
2
2
|
def to_json(*a)
|
3
|
-
%("#{
|
3
|
+
%("#{as_json}")
|
4
4
|
end
|
5
5
|
|
6
|
-
def
|
7
|
-
|
8
|
-
getutc.strftime("%Y/%m/%d %H:%M:%S +0000")
|
9
|
-
else
|
10
|
-
to_s_without_json *args
|
11
|
-
end
|
6
|
+
def as_json(*args)
|
7
|
+
getutc.strftime("%Y/%m/%d %H:%M:%S +0000")
|
12
8
|
end
|
13
|
-
alias_method :to_s_without_json, :to_s
|
14
|
-
alias_method :to_s, :to_s_with_json
|
15
9
|
|
16
10
|
def self.json_create string
|
17
11
|
return nil if string.nil?
|
@@ -63,7 +63,7 @@ module CouchPotato
|
|
63
63
|
|
64
64
|
# saves a document. returns true on success, false on failure
|
65
65
|
def save_document(document, validate = true)
|
66
|
-
return true unless document.dirty?
|
66
|
+
return true unless document.dirty? || document.new?
|
67
67
|
if document.new?
|
68
68
|
create_document(document, validate)
|
69
69
|
else
|
@@ -79,10 +79,10 @@ module CouchPotato
|
|
79
79
|
alias_method :save!, :save_document!
|
80
80
|
|
81
81
|
def destroy_document(document)
|
82
|
-
document.run_callbacks :
|
83
|
-
|
84
|
-
|
85
|
-
|
82
|
+
document.run_callbacks :destroy do
|
83
|
+
document._deleted = true
|
84
|
+
database.delete_doc document.to_hash
|
85
|
+
end
|
86
86
|
document._id = nil
|
87
87
|
document._rev = nil
|
88
88
|
end
|
@@ -102,7 +102,7 @@ module CouchPotato
|
|
102
102
|
alias_method :load, :load_document
|
103
103
|
|
104
104
|
def inspect #:nodoc:
|
105
|
-
"#<CouchPotato::Database>"
|
105
|
+
"#<CouchPotato::Database @root=\"#{database.root}\">"
|
106
106
|
end
|
107
107
|
|
108
108
|
private
|
@@ -112,35 +112,39 @@ module CouchPotato
|
|
112
112
|
|
113
113
|
if validate
|
114
114
|
document.errors.clear
|
115
|
-
document.run_callbacks :
|
116
|
-
|
117
|
-
|
115
|
+
document.run_callbacks :validation_on_save do
|
116
|
+
document.run_callbacks :validation_on_create do
|
117
|
+
return false unless valid_document?(document)
|
118
|
+
end
|
119
|
+
end
|
118
120
|
end
|
119
121
|
|
120
|
-
document.run_callbacks :
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
122
|
+
document.run_callbacks :save do
|
123
|
+
document.run_callbacks :create do
|
124
|
+
res = database.save_doc document.to_hash
|
125
|
+
document._rev = res['rev']
|
126
|
+
document._id = res['id']
|
127
|
+
end
|
128
|
+
end
|
127
129
|
true
|
128
130
|
end
|
129
131
|
|
130
132
|
def update_document(document, validate)
|
131
133
|
if validate
|
132
134
|
document.errors.clear
|
133
|
-
document.run_callbacks :
|
134
|
-
|
135
|
-
|
135
|
+
document.run_callbacks :validation_on_save do
|
136
|
+
document.run_callbacks :validation_on_update do
|
137
|
+
return false unless valid_document?(document)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
document.run_callbacks :save do
|
143
|
+
document.run_callbacks :update do
|
144
|
+
res = database.save_doc document.to_hash
|
145
|
+
document._rev = res['rev']
|
146
|
+
end
|
136
147
|
end
|
137
|
-
|
138
|
-
document.run_callbacks :before_save
|
139
|
-
document.run_callbacks :before_update
|
140
|
-
res = database.save_doc document.to_hash
|
141
|
-
document._rev = res['rev']
|
142
|
-
document.run_callbacks :after_save
|
143
|
-
document.run_callbacks :after_update
|
144
148
|
true
|
145
149
|
end
|
146
150
|
|
@@ -158,4 +162,4 @@ module CouchPotato
|
|
158
162
|
end
|
159
163
|
|
160
164
|
end
|
161
|
-
end
|
165
|
+
end
|
@@ -18,9 +18,10 @@ module CouchPotato
|
|
18
18
|
module Persistence
|
19
19
|
|
20
20
|
def self.included(base) #:nodoc:
|
21
|
-
base.send :include, Properties, Callbacks,
|
21
|
+
base.send :include, Properties, Callbacks, Json, CouchPotato::View::CustomViews, CouchPotato::View::Lists
|
22
22
|
base.send :include, DirtyAttributes, GhostAttributes, Attachments
|
23
23
|
base.send :include, MagicTimestamps, ActiveModelCompliance
|
24
|
+
base.send :include, Validation
|
24
25
|
base.class_eval do
|
25
26
|
attr_accessor :_id, :_rev, :_deleted, :database
|
26
27
|
alias_method :id, :_id
|
@@ -29,7 +30,8 @@ module CouchPotato
|
|
29
30
|
end
|
30
31
|
|
31
32
|
# initialize a new instance of the model optionally passing it a hash of attributes.
|
32
|
-
# the attributes have to be declared using the #property method
|
33
|
+
# the attributes have to be declared using the #property method.
|
34
|
+
# the new model will be yielded to an optionally given block.
|
33
35
|
#
|
34
36
|
# example:
|
35
37
|
# class Book
|
@@ -37,11 +39,20 @@ module CouchPotato
|
|
37
39
|
# property :title
|
38
40
|
# end
|
39
41
|
# book = Book.new :title => 'Time to Relax'
|
42
|
+
#
|
43
|
+
# OR
|
44
|
+
#
|
45
|
+
# book = Book.new do |b|
|
46
|
+
# b.title = 'Time to Relax'
|
47
|
+
# end
|
40
48
|
# book.title # => 'Time to Relax'
|
41
49
|
def initialize(attributes = {})
|
42
|
-
attributes
|
43
|
-
|
44
|
-
|
50
|
+
if attributes
|
51
|
+
attributes.each do |name, value|
|
52
|
+
self.send("#{name}=", value)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
yield self if block_given?
|
45
56
|
end
|
46
57
|
|
47
58
|
# assign multiple attributes at once.
|
@@ -96,6 +107,14 @@ module CouchPotato
|
|
96
107
|
def ==(other) #:nodoc:
|
97
108
|
other.class == self.class && self.to_json == other.to_json
|
98
109
|
end
|
110
|
+
|
111
|
+
def eql?(other)
|
112
|
+
self == other
|
113
|
+
end
|
114
|
+
|
115
|
+
def hash
|
116
|
+
_id.hash * (_id.hash.to_s.size ** 10) + _rev.hash
|
117
|
+
end
|
99
118
|
|
100
119
|
def inspect
|
101
120
|
attributes_as_string = attributes.map {|attribute, value| "#{attribute}: #{value.inspect}"}.join(", ")
|
@@ -1,62 +1,29 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'active_model/callbacks'
|
3
|
+
|
1
4
|
module CouchPotato
|
2
5
|
module Persistence
|
3
6
|
module Callbacks
|
4
7
|
def self.included(base) #:nodoc:
|
5
|
-
base.extend
|
8
|
+
base.extend ActiveModel::Callbacks
|
6
9
|
|
7
10
|
base.class_eval do
|
8
11
|
attr_accessor :skip_callbacks
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
:before_save => [], :after_save => [],
|
14
|
-
:before_destroy => [], :after_destroy => []}
|
15
|
-
end
|
12
|
+
|
13
|
+
define_model_callbacks :create, :save, :update, :destroy
|
14
|
+
define_model_callbacks *[:save, :create, :update].map {|c| :"validation_on_#{c}"}
|
15
|
+
define_model_callbacks :validation unless Config.validation_framework == :active_model
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
19
|
# Runs all callbacks on a model with the given name, e.g. :after_create.
|
20
20
|
#
|
21
21
|
# This method is called by the CouchPotato::Database object when saving/destroying an object
|
22
|
-
def run_callbacks(name)
|
22
|
+
def run_callbacks(name, &block)
|
23
23
|
return if skip_callbacks
|
24
|
-
|
25
|
-
callbacks = self.class.ancestors.map do |clazz|
|
26
|
-
clazz.callbacks[name] if clazz.respond_to?(:callbacks)
|
27
|
-
end.flatten.compact.uniq
|
28
|
-
|
29
|
-
callbacks.each do |callback|
|
30
|
-
if [Symbol, String].include?(callback.class)
|
31
|
-
send callback
|
32
|
-
elsif callback.is_a?(Proc)
|
33
|
-
callback.call self
|
34
|
-
else
|
35
|
-
raise "Don't know how to handle callback of type #{callback.class.name}"
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
24
|
|
40
|
-
|
41
|
-
[
|
42
|
-
:before_validation,
|
43
|
-
:before_validation_on_create,
|
44
|
-
:before_validation_on_update,
|
45
|
-
:before_validation_on_save,
|
46
|
-
:before_create,
|
47
|
-
:before_save,
|
48
|
-
:before_update,
|
49
|
-
:before_destroy,
|
50
|
-
:after_update,
|
51
|
-
:after_save,
|
52
|
-
:after_create,
|
53
|
-
:after_destroy
|
54
|
-
].each do |callback|
|
55
|
-
define_method callback do |*names|
|
56
|
-
callbacks[callback].push *names
|
57
|
-
end
|
58
|
-
end
|
25
|
+
send(:"_run_#{name}_callbacks", &block)
|
59
26
|
end
|
60
27
|
end
|
61
28
|
end
|
62
|
-
end
|
29
|
+
end
|
@@ -4,21 +4,20 @@ module CouchPotato
|
|
4
4
|
module DirtyAttributes
|
5
5
|
|
6
6
|
def self.included(base) #:nodoc:
|
7
|
+
base.send :include, ActiveModel::Dirty
|
7
8
|
base.class_eval do
|
8
9
|
after_save :reset_dirty_attributes
|
9
|
-
|
10
|
-
def initialize(attributes = {})
|
11
|
-
super
|
12
|
-
assign_attribute_copies_for_dirty_tracking
|
13
|
-
end
|
14
10
|
end
|
15
11
|
end
|
16
12
|
|
13
|
+
def initialize(attributes = {})
|
14
|
+
super
|
15
|
+
# assign_attribute_copies_for_dirty_tracking
|
16
|
+
end
|
17
|
+
|
17
18
|
# returns true if a model has dirty attributes, i.e. their value has changed since the last save
|
18
19
|
def dirty?
|
19
|
-
|
20
|
-
res || property.dirty?(self)
|
21
|
-
end
|
20
|
+
changed? || @forced_dirty
|
22
21
|
end
|
23
22
|
|
24
23
|
# marks a model as dirty
|
@@ -26,19 +25,21 @@ module CouchPotato
|
|
26
25
|
@forced_dirty = true
|
27
26
|
end
|
28
27
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
28
|
+
def method_missing(name, *args)
|
29
|
+
if(name.to_s.include?('_will_change!'))
|
30
|
+
self.class.define_attribute_methods self.class.property_names
|
31
|
+
send(name, *args)
|
32
|
+
else
|
33
|
+
super
|
34
|
+
end
|
35
35
|
end
|
36
36
|
|
37
|
+
private
|
38
|
+
|
37
39
|
def reset_dirty_attributes
|
40
|
+
@previously_changed = changes
|
41
|
+
@changed_attributes.clear
|
38
42
|
@forced_dirty = nil
|
39
|
-
self.class.properties.each do |property|
|
40
|
-
instance_variable_set("@#{property.name}_was", clone_attribute(send(property.name)))
|
41
|
-
end
|
42
43
|
end
|
43
44
|
|
44
45
|
def clone_attribute(value)
|
@@ -3,20 +3,25 @@ module CouchPotato
|
|
3
3
|
def self.included(base)
|
4
4
|
base.class_eval do
|
5
5
|
attr_accessor :_document
|
6
|
-
def self.
|
7
|
-
instance =
|
6
|
+
def self.json_create_with_ghost(json)
|
7
|
+
instance = json_create_without_ghost(json)
|
8
8
|
instance._document = json if json
|
9
9
|
instance
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
value
|
15
|
-
else
|
16
|
-
super
|
17
|
-
end
|
12
|
+
class << self
|
13
|
+
alias_method_chain :json_create, :ghost
|
18
14
|
end
|
19
15
|
end
|
20
16
|
end
|
17
|
+
|
18
|
+
def method_missing(name, *args)
|
19
|
+
if(value = _document && _document[name.to_s])
|
20
|
+
value
|
21
|
+
else
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
21
25
|
end
|
22
|
-
end
|
26
|
+
end
|
27
|
+
|
@@ -35,9 +35,12 @@ module CouchPotato
|
|
35
35
|
instance = self.new
|
36
36
|
instance._id = json[:_id] || json['_id']
|
37
37
|
instance._rev = json[:_rev] || json['_rev']
|
38
|
+
instance.instance_variable_set('@skip_dirty_tracking', true)
|
38
39
|
properties.each do |property|
|
39
40
|
property.build(instance, json)
|
40
41
|
end
|
42
|
+
instance.instance_variable_set('@skip_dirty_tracking', false)
|
43
|
+
# instance.instance_variable_get("@changed_attributes").clear if instance.instance_variable_get("@changed_attributes")
|
41
44
|
instance
|
42
45
|
end
|
43
46
|
end
|
@@ -7,13 +7,14 @@ module CouchPotato
|
|
7
7
|
|
8
8
|
before_create lambda {|model|
|
9
9
|
model.created_at ||= Time.now
|
10
|
-
|
10
|
+
@changed_attributes.delete 'created_at'
|
11
11
|
model.updated_at ||= Time.now
|
12
|
-
|
12
|
+
@changed_attributes.delete 'updated_at'
|
13
13
|
}
|
14
14
|
before_update lambda {|model|
|
15
15
|
model.updated_at = Time.now
|
16
|
-
|
16
|
+
@changed_attributes.delete 'updated_at'
|
17
|
+
}
|
17
18
|
end
|
18
19
|
end
|
19
20
|
end
|
@@ -59,13 +59,6 @@ module CouchPotato
|
|
59
59
|
properties.map(&:name)
|
60
60
|
end
|
61
61
|
|
62
|
-
def json_create(json) #:nodoc:
|
63
|
-
return if json.nil?
|
64
|
-
instance = super
|
65
|
-
instance.send(:assign_attribute_copies_for_dirty_tracking)
|
66
|
-
instance
|
67
|
-
end
|
68
|
-
|
69
62
|
# Declare a property on a model class. Properties are not typed by default.
|
70
63
|
# You can store anything in a property that can be serialized into JSON.
|
71
64
|
# If you want a property to be of a custom class you have to define it using the :type option.
|
@@ -37,8 +37,6 @@ module CouchPotato
|
|
37
37
|
|
38
38
|
def define_accessors(base, name, options)
|
39
39
|
base.class_eval do
|
40
|
-
attr_reader "#{name}_was"
|
41
|
-
|
42
40
|
define_method "#{name}" do
|
43
41
|
value = self.instance_variable_get("@#{name}")
|
44
42
|
if value.nil? && options[:default]
|
@@ -51,20 +49,14 @@ module CouchPotato
|
|
51
49
|
end
|
52
50
|
|
53
51
|
define_method "#{name}=" do |value|
|
54
|
-
|
52
|
+
typecasted_value = type_caster.cast(value, options[:type])
|
53
|
+
send("#{name}_will_change!") unless @skip_dirty_tracking || typecasted_value == send(name)
|
54
|
+
self.instance_variable_set("@#{name}", typecasted_value)
|
55
55
|
end
|
56
56
|
|
57
57
|
define_method "#{name}?" do
|
58
58
|
!self.send(name).nil? && !self.send(name).try(:blank?)
|
59
59
|
end
|
60
|
-
|
61
|
-
define_method "#{name}_changed?" do
|
62
|
-
!self.instance_variable_get("@#{name}_not_changed") && self.send(name) != self.send("#{name}_was")
|
63
|
-
end
|
64
|
-
|
65
|
-
define_method "#{name}_not_changed" do
|
66
|
-
self.instance_variable_set("@#{name}_not_changed", true)
|
67
|
-
end
|
68
60
|
end
|
69
61
|
end
|
70
62
|
end
|
@@ -3,15 +3,15 @@ module CouchPotato
|
|
3
3
|
class TypeCaster #:nodoc:
|
4
4
|
def cast(value, type)
|
5
5
|
if type == :boolean
|
6
|
-
|
6
|
+
cast_boolean(value)
|
7
7
|
else
|
8
8
|
cast_native(value, type)
|
9
9
|
end
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
private
|
13
|
-
|
14
|
-
def
|
13
|
+
|
14
|
+
def cast_boolean(value)
|
15
15
|
if [FalseClass, TrueClass].include?(value.class) || value.nil?
|
16
16
|
value
|
17
17
|
elsif [0, '0'].include?(value)
|
@@ -20,13 +20,13 @@ module CouchPotato
|
|
20
20
|
true
|
21
21
|
end
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
def cast_native(value, type)
|
25
25
|
if type && !value.instance_of?(type)
|
26
26
|
if type == Fixnum
|
27
|
-
value.to_s.scan(
|
27
|
+
value.to_s.scan(/-?\d+/).join.to_i unless value.blank?
|
28
28
|
elsif type == Float
|
29
|
-
value.to_s.scan(
|
29
|
+
value.to_s.scan(/-?\d+\.?\d*/).join.to_f unless value.blank?
|
30
30
|
else
|
31
31
|
type.json_create value unless value.blank?
|
32
32
|
end
|
@@ -34,7 +34,7 @@ module CouchPotato
|
|
34
34
|
value
|
35
35
|
end
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
end
|
39
39
|
end
|
40
|
-
end
|
40
|
+
end
|
data/lib/couch_potato/railtie.rb
CHANGED
@@ -1,18 +1,24 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../../rails/reload_classes')
|
2
|
+
require 'erb'
|
2
3
|
|
3
4
|
module CouchPotato
|
4
5
|
def self.rails_init
|
5
|
-
|
6
|
+
config = YAML::load(ERB.new(File.read(Rails.root.join('config/couchdb.yml'))).result)[RAILS_ENV]
|
7
|
+
if config.is_a?(String)
|
8
|
+
CouchPotato::Config.database_name = config
|
9
|
+
else
|
10
|
+
CouchPotato::Config.database_name = config['database']
|
11
|
+
CouchPotato::Config.validation_framework = config['validation_framework']
|
12
|
+
end
|
6
13
|
end
|
7
14
|
|
8
15
|
if defined?(::Rails::Railtie)
|
9
16
|
class Railtie < ::Rails::Railtie
|
10
|
-
|
17
|
+
initializer 'couch_potato.load_config' do |app|
|
11
18
|
CouchPotato.rails_init
|
12
19
|
end
|
13
20
|
end
|
14
21
|
else
|
15
22
|
rails_init
|
16
23
|
end
|
17
|
-
|
18
24
|
end
|
@@ -11,16 +11,20 @@ module CouchPotato
|
|
11
11
|
base.send :include, ::Validatable
|
12
12
|
base.class_eval do
|
13
13
|
# Override the validate method to first run before_validation callback
|
14
|
-
def
|
14
|
+
def valid_with_before_validation_callback?
|
15
15
|
errors.clear
|
16
|
-
run_callbacks :
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
run_callbacks :validation do
|
17
|
+
before_validation_errors = errors.errors.dup
|
18
|
+
valid_without_before_validation_callback?
|
19
|
+
before_validation_errors.each do |k, v|
|
20
|
+
v.each {|message| errors.add(k, message)}
|
21
|
+
end
|
21
22
|
end
|
22
23
|
errors.empty?
|
23
24
|
end
|
25
|
+
|
26
|
+
alias_method :valid_without_before_validation_callback?, :valid?
|
27
|
+
alias_method :valid?, :valid_with_before_validation_callback?
|
24
28
|
end
|
25
29
|
end
|
26
30
|
end
|
@@ -1,4 +1,16 @@
|
|
1
1
|
module CouchPotato
|
2
|
+
# We can bypass creation of views completely, so we can use views
|
3
|
+
# that are created via other means, such as CouchApp.
|
4
|
+
# The default is not to bypass creation.
|
5
|
+
# TODO: enable this bypass for specific view in the view specification, instead of globally
|
6
|
+
def self.bypass_view_creation
|
7
|
+
@bypass_view_creation
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.bypass_view_creation= flag
|
11
|
+
@bypass_view_creation = flag
|
12
|
+
end
|
13
|
+
|
2
14
|
module View
|
3
15
|
# Used to query views (and create them if they don't exist). Usually you won't have to use this class directly. Instead it is used internally by the CouchPotato::Database.view method.
|
4
16
|
class ViewQuery
|
@@ -15,7 +27,7 @@ module CouchPotato
|
|
15
27
|
end
|
16
28
|
|
17
29
|
def query_view!(parameters = {})
|
18
|
-
update_view unless view_has_been_updated?
|
30
|
+
update_view unless CouchPotato::bypass_view_creation || view_has_been_updated?
|
19
31
|
begin
|
20
32
|
query_view parameters
|
21
33
|
rescue RestClient::ResourceNotFound
|
@@ -37,7 +49,9 @@ module CouchPotato
|
|
37
49
|
design_doc['lists'] ||= {}
|
38
50
|
design_doc['lists'][@list_name.to_s] = @list_function
|
39
51
|
end
|
40
|
-
|
52
|
+
# We do not save the design document if view creation is bypassed
|
53
|
+
@database.save_doc(design_doc) unless CouchPotato::bypass_view_creation ||
|
54
|
+
original_views == design_doc['views'] && original_lists == design_doc['lists']
|
41
55
|
end
|
42
56
|
|
43
57
|
def view_functions
|
@@ -49,14 +63,17 @@ module CouchPotato
|
|
49
63
|
end
|
50
64
|
|
51
65
|
def view_has_been_updated?
|
66
|
+
# TODO: decide what to do here in case CouchPotato::bypass_view_creation is true
|
52
67
|
updated_views[[@design_document_name, @view_name]]
|
53
68
|
end
|
54
69
|
|
55
70
|
def view_updated
|
71
|
+
# TODO: decide what to do here in case CouchPotato::bypass_view_creation is true
|
56
72
|
updated_views[[@design_document_name, @view_name]] = true
|
57
73
|
end
|
58
74
|
|
59
75
|
def updated_views
|
76
|
+
# TODO: decide what to do here in case CouchPotato::bypass_view_creation is true
|
60
77
|
@@updated_views ||= {}
|
61
78
|
@@updated_views
|
62
79
|
end
|
data/rails/reload_classes.rb
CHANGED
@@ -7,7 +7,7 @@ module CouchPotato
|
|
7
7
|
begin
|
8
8
|
yield
|
9
9
|
rescue ArgumentError => e
|
10
|
-
if(name = e.message.scan(/(can't find const|undefined class\/module) ([\w\:]+)/).first[1
|
10
|
+
if(name = e.message.scan(/(can't find const|undefined class\/module) ([\w\:]+)/).try(:first).try(:[], 1))
|
11
11
|
eval name.gsub(/\:+$/, '')
|
12
12
|
retry
|
13
13
|
else
|
data/spec/callbacks_spec.rb
CHANGED
@@ -22,9 +22,6 @@ class CallbackRecorder
|
|
22
22
|
|
23
23
|
view :all, :key => :required_property
|
24
24
|
|
25
|
-
attr_accessor :lambda_works
|
26
|
-
before_create lambda {|model| model.lambda_works = true }
|
27
|
-
|
28
25
|
def callbacks
|
29
26
|
@callbacks ||= []
|
30
27
|
end
|
@@ -58,7 +55,7 @@ describe "multiple callbacks at once" do
|
|
58
55
|
|
59
56
|
it "should run all callback methods given to the callback method call" do
|
60
57
|
monkey = Monkey.new
|
61
|
-
monkey.run_callbacks :
|
58
|
+
monkey.run_callbacks :create
|
62
59
|
monkey.eaten_banana.should be_true
|
63
60
|
monkey.eaten_apple.should be_true
|
64
61
|
end
|
@@ -263,14 +260,6 @@ describe "destroy callbacks" do
|
|
263
260
|
end
|
264
261
|
end
|
265
262
|
|
266
|
-
describe "lambda callbacks" do
|
267
|
-
it "should run the lambda" do
|
268
|
-
recorder = CallbackRecorder.new
|
269
|
-
recorder.run_callbacks :before_create
|
270
|
-
recorder.lambda_works.should be_true
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
263
|
describe "validation callbacks" do
|
275
264
|
class ValidatedUser
|
276
265
|
include CouchPotato::Persistence
|
@@ -305,4 +294,4 @@ describe "validation callbacks" do
|
|
305
294
|
user.valid?.should == true
|
306
295
|
user.errors.on(:name).should == nil
|
307
296
|
end
|
308
|
-
end
|
297
|
+
end
|
data/spec/property_spec.rb
CHANGED
data/spec/rails_spec.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require File.dirname(__FILE__) + '/../rails/reload_classes'
|
3
2
|
|
4
3
|
module LoadConst
|
5
4
|
def const_missing(name)
|
@@ -33,7 +32,7 @@ describe CouchPotato::Database, 'rails specific behavior' do
|
|
33
32
|
CouchPotato.couchrest_database.save_doc(JSON.create_id => 'Autoloader::Uninitialized', '_id' => '1')
|
34
33
|
CouchPotato.database.load('1').class.name.should == 'Autoloader::Uninitialized'
|
35
34
|
end
|
36
|
-
|
35
|
+
|
37
36
|
it "should load nested models" do
|
38
37
|
CouchPotato.couchrest_database.save_doc(JSON.create_id => 'Autoloader::Nested::Nested2', '_id' => '1')
|
39
38
|
CouchPotato.database.load('1').class.name.should == 'Autoloader::Nested::Nested2'
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'yaml'
|
3
|
+
require 'spec/mocks'
|
4
|
+
|
5
|
+
RAILS_ENV = 'test'
|
6
|
+
module Rails
|
7
|
+
class Railtie
|
8
|
+
def self.initializer(*args)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.root
|
13
|
+
Spec::Mocks::Mock.new :join => ''
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'couch_potato/railtie'
|
18
|
+
|
19
|
+
describe "railtie" do
|
20
|
+
before(:all) do
|
21
|
+
@validation_framework = CouchPotato::Config.validation_framework
|
22
|
+
end
|
23
|
+
|
24
|
+
after(:all) do
|
25
|
+
CouchPotato::Config.validation_framework = @validation_framework
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'yaml file contains only database names' do
|
29
|
+
it "should set the database name from the yaml file" do
|
30
|
+
File.stub(:read => "test: test_db")
|
31
|
+
|
32
|
+
CouchPotato::Config.should_receive(:database_name=).with('test_db')
|
33
|
+
|
34
|
+
CouchPotato.rails_init
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'yaml file contains more configuration' do
|
39
|
+
before(:each) do
|
40
|
+
File.stub(:read => "test: \n database: test_db\n validation_framework: :active_model")
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should set the database name from the yaml file" do
|
44
|
+
CouchPotato::Config.should_receive(:database_name=).with('test_db')
|
45
|
+
|
46
|
+
CouchPotato.rails_init
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should set the validation framework from the yaml file" do
|
50
|
+
CouchPotato::Config.should_receive(:validation_framework=).with(:active_model)
|
51
|
+
|
52
|
+
CouchPotato.rails_init
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should process the yml file with erb" do
|
57
|
+
File.stub(:read => "test: \n database: <%= 'db' %>")
|
58
|
+
|
59
|
+
CouchPotato::Config.should_receive(:database_name=).with('db')
|
60
|
+
|
61
|
+
CouchPotato.rails_init
|
62
|
+
end
|
63
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -58,6 +58,11 @@ describe "attributes" do
|
|
58
58
|
@plant.typed_leaf_count.should == 4
|
59
59
|
end
|
60
60
|
|
61
|
+
it "should convert a string into a negative fixnum" do
|
62
|
+
@plant.typed_leaf_count = '-4'
|
63
|
+
@plant.typed_leaf_count.should == -4
|
64
|
+
end
|
65
|
+
|
61
66
|
it "should leave a fixnum as is" do
|
62
67
|
@plant.typed_leaf_count = 4
|
63
68
|
@plant.typed_leaf_count.should == 4
|
@@ -94,6 +99,11 @@ describe "attributes" do
|
|
94
99
|
@plant.typed_leaf_size = '5'
|
95
100
|
@plant.typed_leaf_size.should == 5.0
|
96
101
|
end
|
102
|
+
|
103
|
+
it "should convert a negative number in a string" do
|
104
|
+
@plant.typed_leaf_size = '-5.0'
|
105
|
+
@plant.typed_leaf_size.should == -5.0
|
106
|
+
end
|
97
107
|
|
98
108
|
it "should leave a float as it is" do
|
99
109
|
@plant.typed_leaf_size = 0.5
|
data/spec/unit/callbacks_spec.rb
CHANGED
@@ -4,23 +4,15 @@ describe 'callbacks' do
|
|
4
4
|
class Tree
|
5
5
|
include CouchPotato::Persistence
|
6
6
|
|
7
|
-
before_validation :grow_leaf
|
7
|
+
before_validation :grow_leaf
|
8
8
|
|
9
9
|
property :leaf_count
|
10
|
-
property :root_count
|
11
|
-
property :branch_count
|
12
10
|
property :watered
|
13
|
-
|
14
11
|
|
15
12
|
def grow_leaf
|
16
13
|
self.leaf_count ||= 0
|
17
14
|
self.leaf_count += 1
|
18
15
|
end
|
19
|
-
|
20
|
-
def grow_branch
|
21
|
-
self.branch_count ||= 0
|
22
|
-
self.branch_count += 1
|
23
|
-
end
|
24
16
|
end
|
25
17
|
|
26
18
|
class AppleTree < Tree
|
@@ -37,31 +29,13 @@ describe 'callbacks' do
|
|
37
29
|
end
|
38
30
|
end
|
39
31
|
|
40
|
-
it "should call a method from a symbol when validated" do
|
41
|
-
tree = Tree.new(:leaf_count => 1, :root_count => 1)
|
42
|
-
tree.valid?
|
43
|
-
tree.leaf_count.should == 2
|
44
|
-
end
|
45
|
-
|
46
|
-
it "should call a method from a string when validated" do
|
47
|
-
tree = Tree.new(:branch_count => 0)
|
48
|
-
tree.valid?
|
49
|
-
tree.branch_count.should == 1
|
50
|
-
end
|
51
|
-
|
52
|
-
it "should call a lambda when validated" do
|
53
|
-
tree = Tree.new(:leaf_count => 1, :root_count => 1)
|
54
|
-
tree.valid?
|
55
|
-
tree.root_count.should == 2
|
56
|
-
end
|
57
|
-
|
58
32
|
context 'inheritance' do
|
59
33
|
it "should call the callbacks of the super class" do
|
60
34
|
tree = AppleTree.new :leaf_count => 1
|
61
35
|
tree.valid?
|
62
36
|
tree.leaf_count.should == 2
|
63
37
|
end
|
64
|
-
|
38
|
+
|
65
39
|
it "should call the callbacks of the child class" do
|
66
40
|
tree = AppleTree.new :leaf_count => 1
|
67
41
|
tree.valid?
|
@@ -69,4 +43,4 @@ describe 'callbacks' do
|
|
69
43
|
end
|
70
44
|
end
|
71
45
|
|
72
|
-
end
|
46
|
+
end
|
data/spec/unit/database_spec.rb
CHANGED
@@ -119,10 +119,10 @@ describe CouchPotato::Database, 'save_document' do
|
|
119
119
|
it "should not run the validations when saved with false" do
|
120
120
|
category = Category.new(:name => 'food')
|
121
121
|
@db.save_document(category)
|
122
|
-
category.new?.should
|
122
|
+
category.new?.should be_false
|
123
123
|
category.name = nil
|
124
124
|
@db.save_document(category, false)
|
125
|
-
category.dirty?.should
|
125
|
+
category.dirty?.should be_false
|
126
126
|
end
|
127
127
|
|
128
128
|
it "should run the validations when saved with true" do
|
data/spec/unit/date_spec.rb
CHANGED
@@ -7,10 +7,10 @@ describe Date, 'to_json' do
|
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
-
describe Date, '
|
10
|
+
describe Date, 'as_json' do
|
11
11
|
it "should format it in the same way as to_json does so i can use this to do queries over date attributes" do
|
12
12
|
date = Date.parse('2009-01-01')
|
13
|
-
date.
|
13
|
+
date.as_json.should == "2009/01/01"
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -33,24 +33,6 @@ describe 'dirty attribute tracking' do
|
|
33
33
|
@couchrest_db.should_receive(:save_doc)
|
34
34
|
@db.save_document(plate)
|
35
35
|
end
|
36
|
-
|
37
|
-
it "should correctly track dirty hashes (deep clone)" do
|
38
|
-
plate = Plate.new :food => {:veggies => ['carrots', 'peas']}
|
39
|
-
@db.save_document(plate)
|
40
|
-
plate.food[:veggies] << 'beans'
|
41
|
-
@couchrest_db.should_receive(:save_doc)
|
42
|
-
@db.save_document(plate)
|
43
|
-
end
|
44
|
-
|
45
|
-
it "should correctly track dirty hashes (deep clone) after a save" do
|
46
|
-
plate = Plate.new :food => {:veggies => ['carrots', 'peas']}
|
47
|
-
@db.save_document(plate)
|
48
|
-
plate.food[:veggies] << 'beans'
|
49
|
-
@db.save_document(plate)
|
50
|
-
plate.food[:veggies] << 'cauliflower'
|
51
|
-
@couchrest_db.should_receive(:save_doc)
|
52
|
-
@db.save_document(plate)
|
53
|
-
end
|
54
36
|
end
|
55
37
|
|
56
38
|
describe "newly created object" do
|
@@ -67,21 +49,22 @@ describe 'dirty attribute tracking' do
|
|
67
49
|
|
68
50
|
describe "with type BigDecimal" do
|
69
51
|
before(:each) do
|
70
|
-
class
|
52
|
+
class Bowl
|
53
|
+
include CouchPotato::Persistence
|
71
54
|
property :price
|
72
55
|
end
|
73
56
|
end
|
74
57
|
it "should not dup BigDecimal" do
|
75
58
|
|
76
59
|
lambda {
|
77
|
-
|
60
|
+
Bowl.new :price => BigDecimal.new("5.23")
|
78
61
|
}.should_not raise_error(TypeError)
|
79
62
|
end
|
80
63
|
|
81
64
|
it "should return the old value" do
|
82
|
-
|
83
|
-
|
84
|
-
|
65
|
+
bowl = Bowl.new :price => BigDecimal.new("5.23")
|
66
|
+
bowl.price = BigDecimal.new("2.23")
|
67
|
+
bowl.price_was.should == 5.23
|
85
68
|
end
|
86
69
|
|
87
70
|
end
|
@@ -94,13 +77,7 @@ describe 'dirty attribute tracking' do
|
|
94
77
|
end
|
95
78
|
|
96
79
|
it "should return false if attribute not changed" do
|
97
|
-
|
98
|
-
end
|
99
|
-
|
100
|
-
it "should return false if attribute forced not changed" do
|
101
|
-
@plate.food = 'burger'
|
102
|
-
@plate.food_not_changed
|
103
|
-
@plate.should_not be_food_changed
|
80
|
+
Plate.new.should_not be_food_changed
|
104
81
|
end
|
105
82
|
|
106
83
|
it "should return true if forced dirty" do
|
@@ -128,13 +105,6 @@ describe 'dirty attribute tracking' do
|
|
128
105
|
@plate.food = 'burger'
|
129
106
|
@plate.should be_food_changed
|
130
107
|
end
|
131
|
-
|
132
|
-
it "should return true if array attribute changed" do
|
133
|
-
couchrest_db = stub('database', :get => Plate.json_create({'_id' => '1', '_rev' => '2', 'food' => ['sushi'], JSON.create_id => 'Plate'}), :info => nil)
|
134
|
-
plate = CouchPotato::Database.new(couchrest_db).load_document '1'
|
135
|
-
plate.food << 'burger'
|
136
|
-
plate.should be_food_changed
|
137
|
-
end
|
138
108
|
|
139
109
|
it "should return false if attribute not changed" do
|
140
110
|
@plate.should_not be_food_changed
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Document
|
4
|
+
include CouchPotato::Persistence
|
5
|
+
|
6
|
+
property :title
|
7
|
+
property :content
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "new" do
|
11
|
+
context "without arguments" do
|
12
|
+
subject { Document.new }
|
13
|
+
|
14
|
+
it { should be_a(Document) }
|
15
|
+
its(:title) { should be_nil }
|
16
|
+
its(:content) { should be_nil }
|
17
|
+
end
|
18
|
+
|
19
|
+
context "with an argument hash" do
|
20
|
+
subject { Document.new(:title => 'My Title') }
|
21
|
+
|
22
|
+
it { should be_a(Document) }
|
23
|
+
its(:title) { should == 'My Title'}
|
24
|
+
its(:content) { should be_nil }
|
25
|
+
end
|
26
|
+
|
27
|
+
context "yielding to a block" do
|
28
|
+
subject {
|
29
|
+
Document.new(:title => 'My Title') do |doc|
|
30
|
+
doc.content = 'My Content'
|
31
|
+
end
|
32
|
+
}
|
33
|
+
|
34
|
+
it { should be_a(Document) }
|
35
|
+
its(:title) { should == 'My Title'}
|
36
|
+
its(:content) { should == 'My Content'}
|
37
|
+
end
|
38
|
+
end
|
data/spec/unit/time_spec.rb
CHANGED
@@ -7,10 +7,10 @@ describe Time, 'to_json' do
|
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
-
describe Time, '
|
10
|
+
describe Time, 'as_json' do
|
11
11
|
it "should format it in the same way as to_json does so i can use this to do queries over time attributes" do
|
12
12
|
time = Time.parse('2009-01-01 11:12:23 +0200')
|
13
|
-
time.
|
13
|
+
time.as_json.should == "2009/01/01 09:12:23 +0000"
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: davber_couch_potato
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 4
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.4.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- David Bergman
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2011-02-04 00:00:00 -05:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -40,13 +40,28 @@ dependencies:
|
|
40
40
|
requirements:
|
41
41
|
- - ">="
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
hash:
|
43
|
+
hash: 21
|
44
44
|
segments:
|
45
|
+
- 1
|
45
46
|
- 0
|
46
|
-
-
|
47
|
-
version:
|
47
|
+
- 1
|
48
|
+
version: 1.0.1
|
48
49
|
type: :runtime
|
49
50
|
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
name: activemodel
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 3
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
type: :runtime
|
64
|
+
version_requirements: *id003
|
50
65
|
description: Ruby persistence layer for CouchDB
|
51
66
|
email: davber@gmail.com
|
52
67
|
executables: []
|
@@ -111,6 +126,7 @@ files:
|
|
111
126
|
- spec/fixtures/person.rb
|
112
127
|
- spec/property_spec.rb
|
113
128
|
- spec/rails_spec.rb
|
129
|
+
- spec/railtie_spec.rb
|
114
130
|
- spec/spec.opts
|
115
131
|
- spec/spec_helper.rb
|
116
132
|
- spec/unit/active_model_compliance_spec.rb
|
@@ -123,6 +139,7 @@ files:
|
|
123
139
|
- spec/unit/database_spec.rb
|
124
140
|
- spec/unit/date_spec.rb
|
125
141
|
- spec/unit/dirty_attributes_spec.rb
|
142
|
+
- spec/unit/initialize_spec.rb
|
126
143
|
- spec/unit/json_create_id_spec.rb
|
127
144
|
- spec/unit/lists_spec.rb
|
128
145
|
- spec/unit/model_view_spec_spec.rb
|
@@ -180,6 +197,7 @@ test_files:
|
|
180
197
|
- spec/fixtures/person.rb
|
181
198
|
- spec/property_spec.rb
|
182
199
|
- spec/rails_spec.rb
|
200
|
+
- spec/railtie_spec.rb
|
183
201
|
- spec/spec_helper.rb
|
184
202
|
- spec/unit/active_model_compliance_spec.rb
|
185
203
|
- spec/unit/attributes_spec.rb
|
@@ -191,6 +209,7 @@ test_files:
|
|
191
209
|
- spec/unit/database_spec.rb
|
192
210
|
- spec/unit/date_spec.rb
|
193
211
|
- spec/unit/dirty_attributes_spec.rb
|
212
|
+
- spec/unit/initialize_spec.rb
|
194
213
|
- spec/unit/json_create_id_spec.rb
|
195
214
|
- spec/unit/lists_spec.rb
|
196
215
|
- spec/unit/model_view_spec_spec.rb
|