couch_potato 0.2.20 → 0.2.21

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  ## Changes
2
2
 
3
+ ### 0.2.21
4
+ * automatically set a database instance on results of CouchPotato::Database#view (langalex)
5
+ * improved auto loading of unloaded constants - can now load constants that have never been loaded before (langalex)
6
+ * raise exception on invalid parameters passed to a couchdb view query (langalex)
7
+ * when querying a view: pass in ranges as key instead of startkey/endkey, pass in plain value instead of hash with key (langalex)
8
+
3
9
  ### 0.2.20
4
10
  * support for :boolean properties (jweiss)
5
11
  * return the total_rows when querying a view (langalex)
data/VERSION.yml CHANGED
@@ -1,4 +1,5 @@
1
1
  ---
2
+ :build:
2
3
  :major: 0
3
4
  :minor: 2
4
- :patch: 20
5
+ :patch: 21
@@ -13,25 +13,42 @@ module CouchPotato
13
13
  end
14
14
 
15
15
  # executes a view and return the results. you pass in a view spec
16
- # which is usually a result of a SomePersistentClass.view call.
16
+ # which is usually a result of a SomePersistentClass.some_view call.
17
17
  # also return the total_rows returned by CouchDB as an accessor on the results.
18
18
  #
19
19
  # Example:
20
20
  #
21
21
  # class User
22
22
  # include CouchPotato::Persistence
23
- # view :all, key: :created_at
23
+ # property :age
24
+ # view :all, key: :age
24
25
  # end
26
+ # db = CouchPotato.database
25
27
  #
26
- # CouchPotato.database.view(User.all) # => [user1, user2]
27
- # CouchPotato.database.view(User.all).total_rows # => 2
28
+ # db.view(User.all) # => [user1, user2]
29
+ # db.view(User.all).total_rows # => 2
28
30
  #
31
+ # You can pass the usual parameters you can pass to a couchdb view to the view:
32
+ #
33
+ # db.view(User.all(limit: 5, startkey: 2, reduce: false))
34
+ #
35
+ # For your convenience when passing a has with only a key parameter you can just pass in the value
36
+ #
37
+ # db.view(User.all(key: 1)) == db.view(User.all(1))
38
+ #
39
+ # Instead of passing a startkey and endkey you can pass in a key with a range:
40
+ #
41
+ # db.view(User.all(key: 1..20)) == db.view(startkey: 1, endkey: 20) == db.view(User.all(1..20))
42
+ #
29
43
  def view(spec)
30
44
  results = CouchPotato::View::ViewQuery.new(database,
31
45
  spec.design_document, spec.view_name, spec.map_function,
32
46
  spec.reduce_function).query_view!(spec.view_parameters)
33
47
  processed_results = spec.process_results results
34
48
  processed_results.instance_eval "def total_rows; #{results['total_rows']}; end" if results['total_rows']
49
+ processed_results.each do |document|
50
+ document.database = self if document.respond_to?(:database=)
51
+ end if processed_results.respond_to?(:each)
35
52
  processed_results
36
53
  end
37
54
 
@@ -16,7 +16,7 @@ require File.dirname(__FILE__) + '/view/view_query'
16
16
  module CouchPotato
17
17
  module Persistence
18
18
 
19
- def self.included(base)
19
+ def self.included(base) #:nodoc:
20
20
  base.send :include, Properties, Callbacks, Validation, Json, CouchPotato::View::CustomViews
21
21
  base.send :include, DirtyAttributes, GhostAttributes, Attachments
22
22
  base.send :include, MagicTimestamps
@@ -1,6 +1,6 @@
1
1
  module CouchPotato
2
2
  module Attachments
3
- def self.included(base)
3
+ def self.included(base) #:nodoc:
4
4
  base.class_eval do
5
5
  attr_writer :_attachments
6
6
 
@@ -1,7 +1,7 @@
1
1
  module CouchPotato
2
2
  module Persistence
3
3
  module Callbacks
4
- def self.included(base)
4
+ def self.included(base) #:nodoc:
5
5
  base.extend ClassMethods
6
6
 
7
7
  base.class_eval do
@@ -2,7 +2,7 @@ module CouchPotato
2
2
  module Persistence
3
3
  module DirtyAttributes
4
4
 
5
- def self.included(base)
5
+ def self.included(base) #:nodoc:
6
6
  base.class_eval do
7
7
  after_save :reset_dirty_attributes
8
8
 
@@ -1,5 +1,5 @@
1
1
  module CouchPotato
2
- module GhostAttributes
2
+ module GhostAttributes #:nodoc:
3
3
  def self.included(base)
4
4
  base.class_eval do
5
5
  attr_accessor :_document
@@ -1,7 +1,7 @@
1
1
  module CouchPotato
2
2
  module Persistence
3
3
  module Json
4
- def self.included(base)
4
+ def self.included(base) #:nodoc:
5
5
  base.extend ClassMethods
6
6
  end
7
7
 
@@ -32,7 +32,7 @@ module CouchPotato
32
32
  end
33
33
  end
34
34
 
35
- def self.included(base)
35
+ def self.included(base) #:nodoc:
36
36
  base.extend ClassMethods
37
37
  base.class_eval do
38
38
  def self.properties
@@ -42,7 +42,7 @@ module CouchPotato
42
42
  end
43
43
  end
44
44
 
45
- def type_caster
45
+ def type_caster #:nodoc:
46
46
  @type_caster ||= TypeCaster.new
47
47
  end
48
48
 
@@ -1,6 +1,6 @@
1
1
  module CouchPotato
2
2
  module Persistence
3
- class TypeCaster
3
+ class TypeCaster #:nodoc:
4
4
  def cast(value, type)
5
5
  if type == :boolean
6
6
  cast_boolen(value)
@@ -3,7 +3,7 @@ require 'validatable'
3
3
  module CouchPotato
4
4
  module Persistence
5
5
  module Validation
6
- def self.included(base)
6
+ def self.included(base) #:nodoc:
7
7
  base.send :include, Validatable
8
8
  base.class_eval do
9
9
  # Override the validate method to first run before_validation callback
@@ -5,6 +5,8 @@ module CouchPotato
5
5
  private :klass, :options
6
6
 
7
7
  def initialize(klass, view_name, options, view_parameters)
8
+ normalized_view_parameters = normalize_view_parameters view_parameters
9
+ assert_valid_view_parameters normalized_view_parameters
8
10
  @klass = klass
9
11
  @design_document = klass.to_s.underscore
10
12
  @view_name = view_name
@@ -13,12 +15,47 @@ module CouchPotato
13
15
  [:group, :include_docs, :descending, :group_level, :limit].each do |key|
14
16
  @view_parameters[key] = options[key] if options.include?(key)
15
17
  end
16
- @view_parameters.merge!(view_parameters)
18
+ @view_parameters.merge!(normalized_view_parameters)
17
19
  end
18
20
 
19
21
  def process_results(results)
20
22
  results
21
23
  end
24
+
25
+ private
26
+
27
+ def normalize_view_parameters(params)
28
+ normalized_params = params.dup
29
+ hash = wrap_in_hash params
30
+ replace_range_key hash
31
+ end
32
+
33
+ def wrap_in_hash(params)
34
+ if params.is_a?(Hash)
35
+ params
36
+ else
37
+ {:key => params}
38
+ end
39
+ end
40
+
41
+ def replace_range_key(params)
42
+ if((key = params[:key]).is_a?(Range))
43
+ params.delete :key
44
+ params[:startkey] = key.first
45
+ params[:endkey] = key.last
46
+ end
47
+ params
48
+ end
49
+
50
+ def assert_valid_view_parameters(params)
51
+ params.keys.each do |key|
52
+ raise ArgumentError.new("invalid view parameter: #{key}") unless valid_view_parameters.include?(key.to_s)
53
+ end
54
+ end
55
+
56
+ def valid_view_parameters
57
+ %w(key startkey startkey_docid endkey endkey_docid limit stale descending skip group group_level reduce include_docs inclusive_end)
58
+ end
22
59
  end
23
60
  end
24
61
  end
@@ -9,13 +9,12 @@ module CouchPotato
9
9
  module View
10
10
  module CustomViews
11
11
 
12
- def self.included(base)
12
+ def self.included(base) #:nodoc:
13
13
  base.extend ClassMethods
14
14
  end
15
15
 
16
16
  module ClassMethods
17
- # Declare a CouchDB view, for examples on how to use see the *ViewSpec classes in CouchPotato::View
18
- def views(view_name = nil)
17
+ def views(view_name = nil) #:nodoc:
19
18
  if view_name
20
19
  _find_view(view_name)
21
20
  else
@@ -23,10 +22,11 @@ module CouchPotato
23
22
  end
24
23
  end
25
24
 
26
- def execute_view(view_name, view_parameters)
25
+ def execute_view(view_name, view_parameters) #:nodoc:
27
26
  view_spec_class(views(view_name)[:type]).new(self, view_name, views(view_name), view_parameters)
28
27
  end
29
-
28
+
29
+ # Declare a CouchDB view, for examples on how to use see the *ViewSpec classes in CouchPotato::View
30
30
  def view(view_name, options)
31
31
  view_name = view_name.to_s
32
32
  views[view_name] = options
@@ -34,7 +34,7 @@ module CouchPotato
34
34
  self.instance_eval(method_str)
35
35
  end
36
36
 
37
- def view_spec_class(type)
37
+ def view_spec_class(type) #:nodoc:
38
38
  if type && type.is_a?(Class)
39
39
  type
40
40
  else
@@ -43,7 +43,7 @@ module CouchPotato
43
43
  end
44
44
  end
45
45
 
46
- def _find_view(view)
46
+ def _find_view(view) #:nodoc:
47
47
  return @views[view] if @views && @views[view]
48
48
  superclass._find_view(view) if superclass && superclass.respond_to?(:_find_view)
49
49
  end
@@ -1,32 +1,16 @@
1
1
  module CouchPotato
2
- module Persistence
3
-
4
- def self.persistent_classes #:nodoc:
5
- @persistent_classes ||= []
6
- end
7
-
8
- def self.reload_persistent_classes #:nodoc:
9
- persistent_classes.each do |clazz|
10
- eval clazz.name
11
- end
12
- end
13
-
14
-
15
- def self.included_with_class_reloading(base) #:nodoc:
16
- persistent_classes << base
17
- included_without_class_reloading(base)
18
- end
19
-
20
- class << self
21
- alias_method :included_without_class_reloading, :included
22
- alias_method :included, :included_with_class_reloading
23
- end
24
- end
25
-
26
2
  Database.class_eval do
27
3
  def load_document_with_class_reloading(id)
28
- Persistence.reload_persistent_classes
29
- load_document_without_class_reloading id
4
+ begin
5
+ load_document_without_class_reloading id
6
+ rescue ArgumentError => e
7
+ if(name = e.message.scan(/(can't find const|undefined class\/module) ([\w\:]+)/).first[1])
8
+ eval name
9
+ retry
10
+ else
11
+ raise e
12
+ end
13
+ end
30
14
  end
31
15
 
32
16
  alias_method :load_document_without_class_reloading, :load_document
data/spec/rails_spec.rb CHANGED
@@ -10,9 +10,7 @@ end
10
10
 
11
11
  describe CouchPotato::Database, 'rails specific behavior' do
12
12
 
13
- it "should load load models whose constants are currently uninitialized (like with rails in development mode)" do
14
- Autoloader::Uninitialized
15
- Autoloader.send :remove_const, 'Uninitialized'
13
+ it "should load models whose constants are currently uninitialized (like with rails in development mode)" do
16
14
  recreate_db
17
15
  CouchPotato.couchrest_database.save_doc(JSON.create_id => 'Autoloader::Uninitialized', '_id' => '1')
18
16
  CouchPotato.database.load('1').class.name.should == 'Autoloader::Uninitialized'
@@ -0,0 +1,46 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe CouchPotato::View::BaseViewSpec, 'initialize' do
4
+ describe "view parameters" do
5
+ it "should raise an error when passing invalid view parameters" do
6
+ lambda {
7
+ CouchPotato::View::BaseViewSpec.new Object, 'all', {}, {:start_key => '1'}
8
+ }.should raise_error(ArgumentError, "invalid view parameter: start_key")
9
+ end
10
+
11
+ it "should not raise an error when passing valid view parameters" do
12
+ lambda {
13
+ CouchPotato::View::BaseViewSpec.new Object, 'all', {}, {
14
+ :key => 'keyvalue',
15
+ :startkey => 'keyvalue',
16
+ :startkey_docid => 'docid',
17
+ :endkey => 'keyvalue',
18
+ :endkey_docid => 'docid',
19
+ :limit => 3,
20
+ :stale => 'ok',
21
+ :descending => true,
22
+ :skip => 1,
23
+ :group => true,
24
+ :group_level => 1,
25
+ :reduce => false,
26
+ :include_docs => true,
27
+ :inclusive_end => true
28
+ }
29
+ }.should_not raise_error
30
+ end
31
+
32
+ it "should convert a range passed as key into startkey and endkey" do
33
+ spec = CouchPotato::View::BaseViewSpec.new Object, 'all', {}, {:key => '1'..'2'}
34
+ spec.view_parameters.should == {:startkey => '1', :endkey => '2'}
35
+ end
36
+
37
+ it "should convert a plain value to a hash with a key" do
38
+ spec = CouchPotato::View::BaseViewSpec.new Object, 'all', {}, '2'
39
+ spec.view_parameters.should == {:key => '2'}
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+
46
+
@@ -205,3 +205,32 @@ describe CouchPotato::Database, 'save_document' do
205
205
 
206
206
  end
207
207
  end
208
+
209
+ describe CouchPotato::Database, 'view' do
210
+ before(:each) do
211
+ @db = CouchPotato::Database.new(stub('couchrest db').as_null_object)
212
+ @result = stub('result')
213
+ @spec = stub('view spec', :process_results => [@result]).as_null_object
214
+ CouchPotato::View::ViewQuery.stub(:new => stub('view query', :query_view! => {'rows' => [@result]}))
215
+ end
216
+
217
+ it "should set itself on returned results that have an accessor" do
218
+ @result.stub(:respond_to?).with(:database=).and_return(true)
219
+ @result.should_receive(:database=).with(@db)
220
+ @db.view(@spec)
221
+ end
222
+
223
+ it "should not set itself on returned results that don't have an accessor" do
224
+ @result.stub(:respond_to?).with(:database=).and_return(false)
225
+ @result.should_not_receive(:database=).with(@db)
226
+ @db.view(@spec)
227
+ end
228
+
229
+ it "should not try to set itself on result sets that are not collections" do
230
+ lambda {
231
+ @spec.stub(:process_results => 1)
232
+ }.should_not raise_error
233
+
234
+ @db.view(@spec)
235
+ end
236
+ end
@@ -10,4 +10,4 @@ describe CouchPotato::View::ModelViewSpec, 'map_function' do
10
10
  spec = CouchPotato::View::ModelViewSpec.new Object, 'all', {}, {}
11
11
  spec.map_function.should include('if(doc.ruby_class && doc.ruby_class == \'Object\')')
12
12
  end
13
- end
13
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: couch_potato
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.20
4
+ version: 0.2.21
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Lang
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-11 00:00:00 +01:00
12
+ date: 2010-01-13 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -100,6 +100,7 @@ files:
100
100
  - spec/spec.opts
101
101
  - spec/spec_helper.rb
102
102
  - spec/unit/attributes_spec.rb
103
+ - spec/unit/base_view_spec_spec.rb
103
104
  - spec/unit/callbacks_spec.rb
104
105
  - spec/unit/couch_potato_spec.rb
105
106
  - spec/unit/create_spec.rb
@@ -153,6 +154,7 @@ test_files:
153
154
  - spec/rails_spec.rb
154
155
  - spec/spec_helper.rb
155
156
  - spec/unit/attributes_spec.rb
157
+ - spec/unit/base_view_spec_spec.rb
156
158
  - spec/unit/callbacks_spec.rb
157
159
  - spec/unit/couch_potato_spec.rb
158
160
  - spec/unit/create_spec.rb