couchrest_model 2.1.0.rc1 → 2.2.0.beta1

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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.travis.yml +15 -4
  4. data/Gemfile.activesupport-4.x +4 -0
  5. data/Gemfile.activesupport-5.x +4 -0
  6. data/README.md +2 -0
  7. data/VERSION +1 -1
  8. data/couchrest_model.gemspec +3 -2
  9. data/history.md +14 -1
  10. data/lib/couchrest/model/associations.rb +3 -8
  11. data/lib/couchrest/model/base.rb +15 -7
  12. data/lib/couchrest/model/casted_array.rb +22 -34
  13. data/lib/couchrest/model/configuration.rb +2 -0
  14. data/lib/couchrest/model/design.rb +4 -3
  15. data/lib/couchrest/model/designs/view.rb +37 -32
  16. data/lib/couchrest/model/dirty.rb +93 -19
  17. data/lib/couchrest/model/embeddable.rb +2 -14
  18. data/lib/couchrest/model/extended_attachments.rb +2 -4
  19. data/lib/couchrest/model/persistence.rb +14 -17
  20. data/lib/couchrest/model/properties.rb +46 -54
  21. data/lib/couchrest/model/property.rb +0 -3
  22. data/lib/couchrest/model/proxyable.rb +20 -4
  23. data/lib/couchrest/model/validations/uniqueness.rb +4 -1
  24. data/lib/couchrest_model.rb +2 -2
  25. data/spec/fixtures/models/article.rb +1 -1
  26. data/spec/fixtures/models/card.rb +2 -1
  27. data/spec/fixtures/models/person.rb +1 -0
  28. data/spec/fixtures/models/project.rb +3 -0
  29. data/spec/unit/assocations_spec.rb +73 -73
  30. data/spec/unit/attachment_spec.rb +34 -34
  31. data/spec/unit/base_spec.rb +102 -102
  32. data/spec/unit/casted_array_spec.rb +7 -7
  33. data/spec/unit/casted_spec.rb +7 -7
  34. data/spec/unit/configuration_spec.rb +11 -11
  35. data/spec/unit/connection_spec.rb +30 -30
  36. data/spec/unit/core_extensions/{time_parsing.rb → time_parsing_spec.rb} +21 -21
  37. data/spec/unit/design_spec.rb +38 -38
  38. data/spec/unit/designs/design_mapper_spec.rb +26 -26
  39. data/spec/unit/designs/migrations_spec.rb +13 -13
  40. data/spec/unit/designs/view_spec.rb +319 -274
  41. data/spec/unit/designs_spec.rb +39 -39
  42. data/spec/unit/dirty_spec.rb +188 -103
  43. data/spec/unit/embeddable_spec.rb +119 -117
  44. data/spec/unit/inherited_spec.rb +4 -4
  45. data/spec/unit/persistence_spec.rb +122 -122
  46. data/spec/unit/properties_spec.rb +466 -16
  47. data/spec/unit/property_protection_spec.rb +32 -32
  48. data/spec/unit/property_spec.rb +45 -436
  49. data/spec/unit/proxyable_spec.rb +140 -82
  50. data/spec/unit/subclass_spec.rb +14 -14
  51. data/spec/unit/translations_spec.rb +5 -5
  52. data/spec/unit/typecast_spec.rb +131 -131
  53. data/spec/unit/utils/migrate_spec.rb +2 -2
  54. data/spec/unit/validations_spec.rb +31 -31
  55. metadata +27 -12
  56. data/lib/couchrest/model/casted_hash.rb +0 -84
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d9cebaec8e04dcd93d4d5f53740ba5ce5b6af068
4
- data.tar.gz: 71c3fb5e884c883124e05b2d69b60be3f474f7a1
3
+ metadata.gz: dc3de5182b5c551856bd3dbbbdea62fe97feccf8
4
+ data.tar.gz: 1aac104a38f10500bcfbf6d3812442b7fa6ca677
5
5
  SHA512:
6
- metadata.gz: 9cfc97e0e45f07cfadfb6d9bdfe89e7a1437e1ffbb935c6584d0f0d83ebb3fce064490330cc84452ff2237548358ca805e7bdf15d3b8d586b7800235297c91d9
7
- data.tar.gz: 7e0148b1299d685cb49af8c554ef5855b69e47cb270ed120b8ddebc5d2db2cd791f2a88de2689ca799d1b416b31f0886ba5c992b83056eeb496055c521e2dade
6
+ metadata.gz: f5c34608cb902751b5671abc660a23203cd7f340fcc05eefc670be5859f7693bb482bf05c400fd5789abfdd09affd9379ecc6589924b5ac70805a05fc0b81421
7
+ data.tar.gz: 39b5d65f53d8cb283f86fbfa0a3d6c27edea311dede32422cce4a0225cc42f98f2ed672cd65e01f48d176cc18a031f2758bbb12011f5391f7f57800ea88bcd80
data/.gitignore CHANGED
@@ -6,6 +6,6 @@ pkg
6
6
  .bundle
7
7
  couchdb.std*
8
8
  *.*~
9
- Gemfile.lock
9
+ *.lock
10
10
  spec.out
11
11
  *.gem
data/.travis.yml CHANGED
@@ -1,14 +1,25 @@
1
+ language: ruby
2
+ gemfile:
3
+ - Gemfile.activesupport-4.x
4
+ - Gemfile.activesupport-5.x
1
5
  rvm:
2
6
  - 2.3.0
3
- - 2.2.2
7
+ - 2.2.4
4
8
  - 2.1.10
5
9
  - 2.0.0
6
10
  - jruby
11
+ - rbx
7
12
  services: couchdb
8
- matrix:
9
- allow_failures:
10
- - rvm: jruby
11
13
  before_install:
12
14
  - gem install bundler
13
15
  env:
14
16
  - JRUBY_OPTS=--2.0
17
+ matrix:
18
+ allow_failures:
19
+ - rvm: 2.0.0
20
+ gemfile: Gemfile.activesupport-5.x
21
+ - rvm: 2.1.10
22
+ gemfile: Gemfile.activesupport-5.x
23
+ - rvm: jruby
24
+ gemfile: Gemfile.activesupport-5.x
25
+ - rvm: rbx # Has problems with Array#insert inheritence
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+ gemspec
3
+
4
+ gem 'activesupport', '~> 4.0'
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+ gemspec
3
+
4
+ gem 'activesupport', '~> 5.0'
data/README.md CHANGED
@@ -19,6 +19,8 @@ See the [update history](https://github.com/couchrest/couchrest_model/blob/maste
19
19
 
20
20
  ### Upgrading from an earlier version?
21
21
 
22
+ *Pre 2.2:* As of August 2016, dirty tracking has been radically re-factored away from ActiveModel::Dirty, which only has support for basic attributes, into a solution that uses [Hashdiff](https://github.com/liufengyun/hashdiff), more details available in the [pull request](https://github.com/couchrest/couchrest_model/pull/211). The result is that some of ActiveModel's Dirty methods are no longer available, these are: `changes_applied`, `restore_attributes`, `previous_changes`, and `changed_attributes`.
23
+
22
24
  *Pre 2.0:* As of June 2012, couchrest model no longer supports the `view_by` and `view` calls from the model. Views are no only accessed via a design document. If you have older code and wish to upgrade, please ensure you move to the new syntax for using views.
23
25
 
24
26
  *Pre 1.1:* As of April 2011 and the release of version 1.1.0, the default model type key is 'type' instead of 'couchrest-type'. Simply updating your project will not work unless you migrate your data or set the configuration option in your initializers:
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.1.0.rc1
1
+ 2.2.0.beta1
@@ -23,9 +23,10 @@ Gem::Specification.new do |s|
23
23
  s.require_paths = ["lib"]
24
24
 
25
25
  s.add_dependency("couchrest", "2.0.0")
26
- s.add_dependency("activemodel", "~> 4.0")
26
+ s.add_dependency("activemodel", ">= 4.0.2")
27
27
  s.add_dependency("tzinfo", ">= 0.3.22")
28
- s.add_development_dependency("rspec", "~> 2.14.1")
28
+ s.add_dependency("hashdiff", "~> 0.3")
29
+ s.add_development_dependency("rspec", "~> 3.5.0")
29
30
  s.add_development_dependency("rack-test", ">= 0.5.7")
30
31
  s.add_development_dependency("rake", ">= 0.8.0")
31
32
  s.add_development_dependency("test-unit")
data/history.md CHANGED
@@ -1,6 +1,19 @@
1
1
  # CouchRest Model Change History
2
2
 
3
- ## 2.1.0 - 2016-07-06
3
+ ## 2.2.0.beta1 - pending
4
+
5
+ * Radical re-factor of dirty tracking using Hashdiff gem, providing reliable change detection with nested data. ([PR](https://github.com/couchrest/couchrest_model/pull/211) @samlown)
6
+ * Implement proxy for factory methods ([PR](https://github.com/couchrest/couchrest_model/pull/210) @ellneal)
7
+ * Add view option to specify a custom emit value for views ([PR](https://github.com/couchrest/couchrest_model/pull/209) @ellneal)
8
+ * Support proxying to multiple databases ([PR](https://github.com/couchrest/couchrest_model/pull/206) @ellneal)
9
+ * Support concurrent auto design doc updates ([PR](https://github.com/couchrest/couchrest_model/pull/201) @ghempton)
10
+ * Upgrading to rspec 3.5 and adding ActiveSupport 5.X tests (@samlown)
11
+
12
+ ## 2.1.0 - skipped!
13
+
14
+ * No release, moved straight to 2.2.0.
15
+
16
+ ## 2.1.0.rc1 - 2016-07-06
4
17
 
5
18
  * Adding "persistent" connection configuration property (@samlown)
6
19
  * Releasing 2.1.0 off of CouchRest 2.0.0.
@@ -1,12 +1,8 @@
1
1
  module CouchRest
2
2
  module Model
3
+ # Basic support for relationships between CouchRest::Model::Base
3
4
  module Associations
4
-
5
- # Basic support for relationships between CouchRest::Model::Base
6
-
7
- def self.included(base)
8
- base.extend(ClassMethods)
9
- end
5
+ extend ActiveSupport::Concern
10
6
 
11
7
  module ClassMethods
12
8
 
@@ -240,8 +236,7 @@ module CouchRest
240
236
 
241
237
  # Override CastedArray instantiation_and_cast method for a simpler
242
238
  # version that will not try to cast the model.
243
- def instantiate_and_cast(obj, change = true)
244
- couchrest_parent_will_change! if change && use_dirty?
239
+ def instantiate_and_cast(obj)
245
240
  obj.casted_by = casted_by if obj.respond_to?(:casted_by)
246
241
  obj.casted_by_property = casted_by_property if obj.respond_to?(:casted_by_property)
247
242
  obj
@@ -45,19 +45,22 @@ module CouchRest
45
45
  #
46
46
  # Options supported:
47
47
  #
48
- # * :directly_set_attributes, true when data comes directly from database
48
+ # * :write_all_attributes, true when data comes directly from database so we can set protected and read-only attributes.
49
49
  # * :database, provide an alternative database
50
50
  #
51
51
  # If a block is provided the new model will be passed into the
52
52
  # block so that it can be populated.
53
- def initialize(attributes = {}, options = {})
53
+ def initialize(attributes = {}, options = {}, &block)
54
54
  super()
55
- prepare_all_attributes(attributes, options)
56
- # set the instance's database, if provided
55
+
56
+ # Always force the type of model
57
+ self[self.model_type_key] = self.class.model_type_value
58
+
59
+ # Some instances may require a different database
57
60
  self.database = options[:database] unless options[:database].nil?
58
- unless self['_id'] && self['_rev']
59
- self[self.model_type_key] = self.class.model_type_value
60
- end
61
+
62
+ # Deal with the attributes
63
+ write_attributes_for_initialization(attributes, options)
61
64
 
62
65
  yield self if block_given?
63
66
 
@@ -65,6 +68,11 @@ module CouchRest
65
68
  run_callbacks(:initialize) { self }
66
69
  end
67
70
 
71
+ def self.build(attrs = {}, options = {}, &block)
72
+
73
+
74
+ end
75
+
68
76
  alias :new_record? :new?
69
77
  alias :new_document? :new?
70
78
 
@@ -5,6 +5,7 @@
5
5
 
6
6
  module CouchRest::Model
7
7
  class CastedArray < Array
8
+ include CouchRest::Model::Configuration
8
9
  include CouchRest::Model::CastedBy
9
10
  include CouchRest::Model::Dirty
10
11
  attr_accessor :casted_by_property
@@ -29,43 +30,15 @@ module CouchRest::Model
29
30
  super(instantiate_and_cast(obj))
30
31
  end
31
32
 
32
- def []= index, obj
33
- value = instantiate_and_cast(obj, false)
34
- couchrest_parent_will_change! if use_dirty? && value != self[index]
35
- super(index, value)
33
+ def []=(index, obj)
34
+ super(index, instantiate_and_cast(obj))
36
35
  end
37
36
 
38
- def insert index, *args
39
- values = *args.map{|obj| instantiate_and_cast(obj, false)}
40
- couchrest_parent_will_change! if use_dirty?
37
+ def insert(index, *args)
38
+ values = args.map{|obj| instantiate_and_cast(obj)}
41
39
  super(index, *values)
42
40
  end
43
41
 
44
- def pop
45
- couchrest_parent_will_change! if use_dirty? && self.length > 0
46
- super
47
- end
48
-
49
- def shift
50
- couchrest_parent_will_change! if use_dirty? && self.length > 0
51
- super
52
- end
53
-
54
- def clear
55
- couchrest_parent_will_change! if use_dirty? && self.length > 0
56
- super
57
- end
58
-
59
- def delete(obj)
60
- couchrest_parent_will_change! if use_dirty? && self.length > 0
61
- super(obj)
62
- end
63
-
64
- def delete_at(index)
65
- couchrest_parent_will_change! if use_dirty? && self.length > 0
66
- super(index)
67
- end
68
-
69
42
  def build(*args)
70
43
  obj = casted_by_property.build(*args)
71
44
  self.push(obj)
@@ -76,11 +49,26 @@ module CouchRest::Model
76
49
  map{ |v| (v.respond_to?(:as_couch_json) ? v.as_couch_json : v)}
77
50
  end
78
51
 
52
+ # Overwrite the standard dirty tracking clearing.
53
+ # We don't have any properties, but we do need to check
54
+ # entries in our array.
55
+ def clear_changes_information
56
+ if use_dirty?
57
+ each do |val|
58
+ if val.respond_to?(:clear_changes_information)
59
+ val.clear_changes_information
60
+ end
61
+ end
62
+ @original_change_data = current_change_data
63
+ else
64
+ @original_change_data = nil
65
+ end
66
+ end
67
+
79
68
  protected
80
69
 
81
- def instantiate_and_cast(obj, change = true)
70
+ def instantiate_and_cast(obj)
82
71
  property = casted_by_property
83
- couchrest_parent_will_change! if change && use_dirty?
84
72
  if casted_by && property && obj.class != property.type
85
73
  property.cast_value(casted_by, obj)
86
74
  else
@@ -15,12 +15,14 @@ module CouchRest
15
15
  add_config :connection
16
16
  add_config :connection_config_file
17
17
  add_config :time_fraction_digits
18
+ add_config :disable_dirty_tracking
18
19
 
19
20
  configure do |config|
20
21
  config.model_type_key = 'type' # was 'couchrest-type'
21
22
  config.mass_assign_any_attribute = false
22
23
  config.auto_update_design_doc = true
23
24
  config.time_fraction_digits = 3
25
+ config.disable_dirty_tracking = false
24
26
 
25
27
  config.environment = :development
26
28
  config.connection_config_file = File.join(Dir.pwd, 'config', 'couchdb.yml')
@@ -17,6 +17,7 @@ module CouchRest
17
17
  def initialize(model, prefix = nil)
18
18
  self.model = model
19
19
  self.method_name = self.class.method_name(prefix)
20
+ @lock = Mutex.new
20
21
  suffix = prefix ? "_#{prefix}" : ''
21
22
  self["_id"] = "_design/#{model.to_s}#{suffix}"
22
23
  apply_defaults
@@ -26,7 +27,8 @@ module CouchRest
26
27
  if auto_update
27
28
  db ||= database
28
29
  if cache_checksum(db) != checksum
29
- sync!(db)
30
+ # Only allow one thread to update the design document at a time
31
+ @lock.synchronize { sync!(db) }
30
32
  set_cache_checksum(db, checksum)
31
33
  end
32
34
  end
@@ -39,6 +41,7 @@ module CouchRest
39
41
  # Load up the last copy. We never blindly overwrite the remote copy
40
42
  # as it may contain views that are not used or known about by
41
43
  # our model.
44
+
42
45
  doc = load_from_database(db)
43
46
 
44
47
  if !doc || doc['couchrest-hash'] != checksum
@@ -181,5 +184,3 @@ module CouchRest
181
184
  end
182
185
  end
183
186
  end
184
-
185
-
@@ -5,10 +5,10 @@ module CouchRest
5
5
  #
6
6
  # A proxy class that allows view queries to be created using
7
7
  # chained method calls. After each call a new instance of the method
8
- # is created based on the original in a similar fashion to ruby's Sequel
8
+ # is created based on the original in a similar fashion to ruby's Sequel
9
9
  # library, or Rails 3's Arel.
10
10
  #
11
- # CouchDB views have inherent limitations, so joins and filters as used in
11
+ # CouchDB views have inherent limitations, so joins and filters as used in
12
12
  # a normal relational database are not possible.
13
13
  #
14
14
  class View
@@ -52,7 +52,7 @@ module CouchRest
52
52
  # == View Execution Methods
53
53
  #
54
54
  # Request to the CouchDB database using the current query values.
55
-
55
+
56
56
  # Return each row wrapped in a ViewRow object. Unlike the raw
57
57
  # CouchDB request, this will provide an empty array if there
58
58
  # are no results.
@@ -65,7 +65,7 @@ module CouchRest
65
65
  else
66
66
  if execute && result['rows']
67
67
  @rows ||= result['rows'].map{|v| ViewRow.new(v, model, use_database)}
68
- else
68
+ else
69
69
  [ ]
70
70
  end
71
71
  end
@@ -81,7 +81,7 @@ module CouchRest
81
81
  end
82
82
 
83
83
  # Provide all the documents from the view. If the view has not been
84
- # prepared with the +include_docs+ option, each document will be
84
+ # prepared with the +include_docs+ option, each document will be
85
85
  # loaded individually.
86
86
  def docs
87
87
  if block_given?
@@ -93,17 +93,17 @@ module CouchRest
93
93
  end
94
94
  end
95
95
 
96
- # If another request has been made on the view, this will return
96
+ # If another request has been made on the view, this will return
97
97
  # the first document in the set. If not, a new query object will be
98
- # generated with a limit of 1 so that only the first document is
98
+ # generated with a limit of 1 so that only the first document is
99
99
  # loaded.
100
100
  def first
101
101
  result ? all.first : limit(1).all.first
102
102
  end
103
103
 
104
104
  # Same as first but will order the view in descending order. This
105
- # does not however reverse the search keys or the offset, so if you
106
- # are using a +startkey+ and +endkey+ you might end up with
105
+ # does not however reverse the search keys or the offset, so if you
106
+ # are using a +startkey+ and +endkey+ you might end up with
107
107
  # unexpected results.
108
108
  #
109
109
  # If in doubt, don't use this method!
@@ -127,7 +127,7 @@ module CouchRest
127
127
  #
128
128
  # Trying to use this method with the group option will raise an error.
129
129
  #
130
- # If no reduce function is defined, a query will be performed
130
+ # If no reduce function is defined, a query will be performed
131
131
  # to return the total number of rows, this is the equivalant of:
132
132
  #
133
133
  # view.limit(0).total_rows
@@ -142,7 +142,7 @@ module CouchRest
142
142
  end
143
143
  end
144
144
 
145
- # Check to see if the array of documents is empty. This *will*
145
+ # Check to see if the array of documents is empty. This *will*
146
146
  # perform the query and return all documents ready to use, if you don't
147
147
  # want to load anything, use +#total_rows+ or +#count+ instead.
148
148
  def empty?
@@ -181,7 +181,7 @@ module CouchRest
181
181
  #
182
182
  # In this example, the raw option will be ignored, and the total rows
183
183
  # will still be accessible.
184
- #
184
+ #
185
185
  def [](value)
186
186
  execute[value]
187
187
  end
@@ -194,8 +194,8 @@ module CouchRest
194
194
 
195
195
 
196
196
  # == View Filter Methods
197
- #
198
- # View filters return a copy of the view instance with the query
197
+ #
198
+ # View filters return a copy of the view instance with the query
199
199
  # modified appropriatly. Errors will be raised if the methods
200
200
  # are combined in an incorrect fashion.
201
201
  #
@@ -208,10 +208,10 @@ module CouchRest
208
208
  update_query(:key => value)
209
209
  end
210
210
 
211
- # Find all index keys that start with the value provided. May or may
211
+ # Find all index keys that start with the value provided. May or may
212
212
  # not be used in conjunction with the +endkey+ option.
213
213
  #
214
- # When the +#descending+ option is used (not the default), the start
214
+ # When the +#descending+ option is used (not the default), the start
215
215
  # and end keys should be reversed, as per the CouchDB API.
216
216
  #
217
217
  # Cannot be used if the key has been set.
@@ -220,7 +220,7 @@ module CouchRest
220
220
  update_query(:startkey => value)
221
221
  end
222
222
 
223
- # The result set should start from the position of the provided document.
223
+ # The result set should start from the position of the provided document.
224
224
  # The value may be provided as an object that responds to the +#id+ call
225
225
  # or a string.
226
226
  def startkey_doc(value)
@@ -237,19 +237,19 @@ module CouchRest
237
237
  update_query(:endkey => value)
238
238
  end
239
239
 
240
- # The result set should end at the position of the provided document.
241
- # The value may be provided as an object that responds to the +#id+
240
+ # The result set should end at the position of the provided document.
241
+ # The value may be provided as an object that responds to the +#id+
242
242
  # call or a string.
243
243
  def endkey_doc(value)
244
244
  update_query(:endkey_docid => value.is_a?(String) ? value : value.id)
245
245
  end
246
246
 
247
247
  # Keys is a special CouchDB option that will cause the view request to be POSTed
248
- # including an array of keys. Only documents with the matching keys will be
249
- # returned. This is much faster than sending multiple requests for a set
248
+ # including an array of keys. Only documents with the matching keys will be
249
+ # returned. This is much faster than sending multiple requests for a set
250
250
  # non-consecutive documents.
251
251
  #
252
- # If no values are provided, this method will act as a wrapper around
252
+ # If no values are provided, this method will act as a wrapper around
253
253
  # the rows result set, providing an array of keys.
254
254
  def keys(*keys)
255
255
  if keys.empty?
@@ -302,16 +302,16 @@ module CouchRest
302
302
  # Control whether the reduce function reduces to a set of distinct keys
303
303
  # or to a single result row.
304
304
  #
305
- # By default the value is false, and can only be set when the view's
305
+ # By default the value is false, and can only be set when the view's
306
306
  # +#reduce+ option has been set.
307
307
  def group
308
308
  raise "View#reduce must have been set before grouping is permitted" unless query[:reduce]
309
309
  update_query(:group => true)
310
310
  end
311
311
 
312
- # Will set the level the grouping should be performed to. As per the
312
+ # Will set the level the grouping should be performed to. As per the
313
313
  # CouchDB API, it only makes sense when the index key is an array.
314
- #
314
+ #
315
315
  # This will automatically set the group option.
316
316
  def group_level(value)
317
317
  group.update_query(:group_level => value.to_i)
@@ -325,7 +325,7 @@ module CouchRest
325
325
 
326
326
  # Allow the results of a query to be provided "stale". Setting to 'ok'
327
327
  # will disable all view updates for the query.
328
- # When 'update_after' is provided the index will be update after the
328
+ # When 'update_after' is provided the index will be update after the
329
329
  # result has been returned.
330
330
  def stale(value)
331
331
  unless (['ok', 'update_after'].include?(value.to_s))
@@ -445,17 +445,17 @@ module CouchRest
445
445
  create_model_methods(design_doc, name, opts)
446
446
  end
447
447
 
448
- # Simplified view definition. A new view will be added to the
448
+ # Simplified view definition. A new view will be added to the
449
449
  # provided design document using the name and options.
450
450
  #
451
- # If the view name starts with "by_" and +:by+ is not provided in
451
+ # If the view name starts with "by_" and +:by+ is not provided in
452
452
  # the options, the new view's map method will be interpreted and
453
453
  # generated automatically. For example:
454
454
  #
455
455
  # View.define(Meeting, design, "by_date_and_name")
456
456
  #
457
- # Will create a view that searches by the date and name properties.
458
- # Explicity setting the attributes to use is possible using the
457
+ # Will create a view that searches by the date and name properties.
458
+ # Explicity setting the attributes to use is possible using the
459
459
  # +:by+ option. For example:
460
460
  #
461
461
  # View.define(Meeting, design, "by_date_and_name", :by => [:date, :firstname, :lastname])
@@ -491,18 +491,23 @@ module CouchRest
491
491
  end
492
492
  raise "View cannot be created without recognised name, :map or :by options" if opts[:by].nil?
493
493
 
494
+ # convert emit symbols to properties
495
+ opts[:emit] = "doc['#{opts[:emit]}']" if opts[:emit].is_a?(Symbol)
496
+ opts[:emit] = "[" + opts[:emit].map { |i| i.is_a?(Symbol) ? "doc['#{i}']" : i }.join(', ') + "]" if opts[:emit].is_a?(Array)
497
+
494
498
  opts[:allow_blank] = opts[:allow_blank].nil? ? true : opts[:allow_blank]
495
499
  opts[:guards] ||= []
496
500
  opts[:guards].push "(doc['#{model.model_type_key}'] == '#{model.model_type_value}')"
497
501
 
498
502
  keys = opts[:by].map{|o| "doc['#{o}']"}
499
- emit = keys.length == 1 ? keys.first : "[#{keys.join(', ')}]"
503
+ emit_keys = keys.length == 1 ? keys.first : "[#{keys.join(', ')}]"
504
+ emit_value = opts[:emit] || 1;
500
505
  opts[:guards] += keys.map{|k| "(#{k} != null)"} unless opts[:allow_nil]
501
506
  opts[:guards] += keys.map{|k| "(#{k} != '')"} unless opts[:allow_blank]
502
507
  opts[:map] = <<-EOF
503
508
  function(doc) {
504
509
  if (#{opts[:guards].join(' && ')}) {
505
- emit(#{emit}, 1);
510
+ emit(#{emit_keys}, #{emit_value});
506
511
  }
507
512
  }
508
513
  EOF