couch_potato 0.3.0 → 0.3.1

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/README.md CHANGED
@@ -18,6 +18,13 @@ Lastly Couch Potato aims to provide a seamless integration with Ruby on Rails, e
18
18
  * declarative views with either custom or generated map/reduce functions
19
19
  * extensive spec suite
20
20
 
21
+ ### Supported Environments
22
+
23
+ * Ruby 1.8.7, 1.9.1, 1.9.2
24
+ * CouchDB 1.0.1
25
+
26
+ (Supported means I run the specs against those before releasing a new gem.)
27
+
21
28
  ### Installation
22
29
 
23
30
  Couch Potato is hosted as a gem which you can install like this:
@@ -54,9 +61,19 @@ Add to your config/environment.rb:
54
61
 
55
62
  Then create a config/couchdb.yml:
56
63
 
57
- development: development_db_name
58
- test: test_db_name
59
- production: http://db.server/production_db_name
64
+ default: &default
65
+ validation_framework: :active_model #optional
66
+
67
+ development:
68
+ <<: *default
69
+ database: development_db_name
70
+ test:
71
+ <<: *default
72
+ database: test_db_name
73
+ production:
74
+ <<: *default
75
+ database: <%= ENV['DB_NAME'] %>
76
+
60
77
 
61
78
  Alternatively you can also install Couch Potato directly as a plugin.
62
79
 
data/VERSION.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- :major: 0
3
2
  :minor: 3
4
- :patch: 0
3
+ :patch: 1
5
4
  :build:
5
+ :major: 0
@@ -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)
@@ -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 :before_destroy
83
- document._deleted = true
84
- database.delete_doc document.to_hash
85
- document.run_callbacks :after_destroy
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 :before_validation_on_save
116
- document.run_callbacks :before_validation_on_create
117
- return false unless valid_document?(document)
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 :before_save
121
- document.run_callbacks :before_create
122
- res = database.save_doc document.to_hash
123
- document._rev = res['rev']
124
- document._id = res['id']
125
- document.run_callbacks :after_save
126
- document.run_callbacks :after_create
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 :before_validation_on_save
134
- document.run_callbacks :before_validation_on_update
135
- return false unless valid_document?(document)
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
@@ -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 ClassMethods
8
+ base.extend ActiveModel::Callbacks
6
9
 
7
10
  base.class_eval do
8
11
  attr_accessor :skip_callbacks
9
- def self.callbacks #:nodoc:
10
- @callbacks ||= {:before_validation => [], :before_validation_on_create => [],
11
- :before_validation_on_update => [], :before_validation_on_save => [], :before_create => [],
12
- :after_create => [], :before_update => [], :after_update => [],
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
- module ClassMethods
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
@@ -6,14 +6,14 @@ module CouchPotato
6
6
  def self.included(base) #:nodoc:
7
7
  base.class_eval do
8
8
  after_save :reset_dirty_attributes
9
-
10
- def initialize(attributes = {})
11
- super
12
- assign_attribute_copies_for_dirty_tracking
13
- end
14
9
  end
15
10
  end
16
11
 
12
+ def initialize(attributes = {})
13
+ super
14
+ assign_attribute_copies_for_dirty_tracking
15
+ end
16
+
17
17
  # returns true if a model has dirty attributes, i.e. their value has changed since the last save
18
18
  def dirty?
19
19
  new? || @forced_dirty || self.class.properties.inject(false) do |res, property|
@@ -8,15 +8,16 @@ module CouchPotato
8
8
  instance._document = json if json
9
9
  instance
10
10
  end
11
-
12
- def method_missing(name, *args)
13
- if(value = _document && _document[name.to_s])
14
- value
15
- else
16
- super
17
- end
18
- end
19
11
  end
20
12
  end
13
+
14
+ def method_missing(name, *args)
15
+ if(value = _document && _document[name.to_s])
16
+ value
17
+ else
18
+ super
19
+ end
20
+ end
21
+
21
22
  end
22
23
  end
@@ -3,15 +3,15 @@ module CouchPotato
3
3
  class TypeCaster #:nodoc:
4
4
  def cast(value, type)
5
5
  if type == :boolean
6
- cast_boolen(value)
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 cast_boolen(value)
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,7 +20,7 @@ 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
@@ -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
@@ -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, Validation, Json, CouchPotato::View::CustomViews, CouchPotato::View::Lists
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
@@ -1,19 +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
5
  def self.rails_init
6
- CouchPotato::Config.database_name = YAML::load(File.read(Rails.root.join('config/couchdb.yml')))[Rails.env]
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
7
13
  end
8
14
 
9
15
  if defined?(::Rails::Railtie)
10
16
  class Railtie < ::Rails::Railtie
11
- config.after_initialize do |app|
17
+ initializer 'couch_potato.load_config' do |app|
12
18
  CouchPotato.rails_init
13
19
  end
14
20
  end
15
21
  else
16
22
  rails_init
17
23
  end
18
-
19
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 valid?
14
+ def valid_with_before_validation_callback?
15
15
  errors.clear
16
- run_callbacks :before_validation
17
- before_validation_errors = errors.errors.dup
18
- super
19
- before_validation_errors.each do |k, v|
20
- v.each {|message| errors.add(k, message)}
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
@@ -35,7 +35,7 @@ module CouchPotato
35
35
  if count?
36
36
  results['rows'].first.try(:[], 'value') || 0
37
37
  else
38
- results['rows'].map { |row| row['doc'] }
38
+ results['rows'].map { |row| row['doc'] || row['id'] }
39
39
  end
40
40
  end
41
41
 
@@ -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 :before_create
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
@@ -33,6 +33,13 @@ describe 'view' do
33
33
  results = @db.view(Build.timeline)
34
34
  results.map(&:class).should == [Build]
35
35
  end
36
+
37
+ it "should return the ids if there document was not included" do
38
+ build = Build.new(:state => 'success', :time => '2008-01-01')
39
+ @db.save_document build
40
+ results = @db.view(Build.timeline(:include_docs => false))
41
+ results.should == [build.id]
42
+ end
36
43
 
37
44
  it "should pass the view options to the view query" do
38
45
  query = mock 'query'
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
- require File.join(File.dirname(__FILE__), 'fixtures', 'address')
3
- require File.join(File.dirname(__FILE__), 'fixtures', 'person')
2
+ require 'fixtures/address'
3
+ require 'fixtures/person'
4
4
 
5
5
  class Watch
6
6
  include CouchPotato::Persistence
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)
@@ -0,0 +1,55 @@
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
+ context 'yaml file contains only database names' do
21
+ it "should set the database name from the yaml file" do
22
+ File.stub(:read => "test: test_db")
23
+
24
+ CouchPotato::Config.should_receive(:database_name=).with('test_db')
25
+
26
+ CouchPotato.rails_init
27
+ end
28
+ end
29
+
30
+ context 'yaml file contains more configuration' do
31
+ before(:each) do
32
+ File.stub(:read => "test: \n database: test_db\n validation_framework: :active_model")
33
+ end
34
+
35
+ it "should set the database name from the yaml file" do
36
+ CouchPotato::Config.should_receive(:database_name=).with('test_db')
37
+
38
+ CouchPotato.rails_init
39
+ end
40
+
41
+ it "should set the validation framework from the yaml file" do
42
+ CouchPotato::Config.should_receive(:validation_framework=).with(:active_model)
43
+
44
+ CouchPotato.rails_init
45
+ end
46
+ end
47
+
48
+ it "should process the yml file with erb" do
49
+ File.stub(:read => "test: \n database: <%= 'db' %>")
50
+
51
+ CouchPotato::Config.should_receive(:database_name=).with('db')
52
+
53
+ CouchPotato.rails_init
54
+ end
55
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'spec'
3
+ require 'time'
3
4
 
4
5
  $:.unshift(File.dirname(__FILE__) + '/../lib')
5
6
 
@@ -4,23 +4,15 @@ describe 'callbacks' do
4
4
  class Tree
5
5
  include CouchPotato::Persistence
6
6
 
7
- before_validation :grow_leaf, 'grow_branch', lambda {|tree| tree.root_count ||= 0; tree.root_count += 1 }
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
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: couch_potato
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 17
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
7
8
  - 3
8
- - 0
9
- version: 0.3.0
9
+ - 1
10
+ version: 0.3.1
10
11
  platform: ruby
11
12
  authors:
12
13
  - Alexander Lang
@@ -14,16 +15,18 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-07-23 00:00:00 +02:00
18
+ date: 2010-09-23 00:00:00 +02:00
18
19
  default_executable:
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
21
22
  name: json
22
23
  prerelease: false
23
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
24
26
  requirements:
25
27
  - - ">="
26
28
  - !ruby/object:Gem::Version
29
+ hash: 3
27
30
  segments:
28
31
  - 0
29
32
  version: "0"
@@ -33,15 +36,32 @@ dependencies:
33
36
  name: couchrest
34
37
  prerelease: false
35
38
  requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
36
40
  requirements:
37
41
  - - ">="
38
42
  - !ruby/object:Gem::Version
43
+ hash: 21
39
44
  segments:
45
+ - 1
40
46
  - 0
41
- - 24
42
- version: "0.24"
47
+ - 1
48
+ version: 1.0.1
43
49
  type: :runtime
44
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
45
65
  description: Ruby persistence layer for CouchDB
46
66
  email: alex@upstream-berlin.com
47
67
  executables: []
@@ -106,6 +126,7 @@ files:
106
126
  - spec/fixtures/person.rb
107
127
  - spec/property_spec.rb
108
128
  - spec/rails_spec.rb
129
+ - spec/railtie_spec.rb
109
130
  - spec/spec.opts
110
131
  - spec/spec_helper.rb
111
132
  - spec/unit/active_model_compliance_spec.rb
@@ -140,23 +161,27 @@ rdoc_options:
140
161
  require_paths:
141
162
  - lib
142
163
  required_ruby_version: !ruby/object:Gem::Requirement
164
+ none: false
143
165
  requirements:
144
166
  - - ">="
145
167
  - !ruby/object:Gem::Version
168
+ hash: 3
146
169
  segments:
147
170
  - 0
148
171
  version: "0"
149
172
  required_rubygems_version: !ruby/object:Gem::Requirement
173
+ none: false
150
174
  requirements:
151
175
  - - ">="
152
176
  - !ruby/object:Gem::Version
177
+ hash: 3
153
178
  segments:
154
179
  - 0
155
180
  version: "0"
156
181
  requirements: []
157
182
 
158
183
  rubyforge_project:
159
- rubygems_version: 1.3.6
184
+ rubygems_version: 1.3.7
160
185
  signing_key:
161
186
  specification_version: 3
162
187
  summary: Ruby persistence layer for CouchDB
@@ -171,6 +196,7 @@ test_files:
171
196
  - spec/fixtures/person.rb
172
197
  - spec/property_spec.rb
173
198
  - spec/rails_spec.rb
199
+ - spec/railtie_spec.rb
174
200
  - spec/spec_helper.rb
175
201
  - spec/unit/active_model_compliance_spec.rb
176
202
  - spec/unit/attributes_spec.rb