couchbase-model 0.5.2 → 0.5.3

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.
@@ -1,4 +1,12 @@
1
- ## 0.5.1 / 2013-02-25
1
+ ## 0.5.3 / 2013-06-06
2
+
3
+ * Prefer single-quoted strings (Andrey Koleshko)
4
+ * Test for Model.design_document (Andrey Koleshko)
5
+ * Support for batch finding multiple objects by id (Jon Moses)
6
+ * Test for activemodel instead of rails for activemodel validations
7
+ * Update couchbase dependency to 1.3.0
8
+
9
+ ## 0.5.2 / 2013-02-25
2
10
 
3
11
  * Fix attribute inheritance when subclassing (Mike Evans)
4
12
  * Added as_json method for rails JSON responses (Stephen von Takach)
@@ -1,23 +1,24 @@
1
1
  # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "couchbase/model/version"
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'couchbase/model/version'
4
4
 
5
5
  Gem::Specification.new do |s|
6
- s.name = "couchbase-model"
6
+ s.name = 'couchbase-model'
7
7
  s.version = Couchbase::Model::VERSION
8
- s.author = "Couchbase"
9
- s.email = "support@couchbase.com"
10
- s.homepage = "https://github.com/couchbase/couchbase-ruby-model"
8
+ s.author = 'Couchbase'
9
+ s.email = 'support@couchbase.com'
10
+ s.homepage = 'https://github.com/couchbase/couchbase-ruby-model'
11
11
  s.summary = %q{Declarative interface to Couchbase}
12
12
  s.description = %q{ORM-like interface allows you to persist your models to Couchbase}
13
13
 
14
14
  s.files = `git ls-files`.split("\n")
15
15
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
16
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
- s.require_paths = ["lib"]
17
+ s.require_paths = ['lib']
18
18
 
19
- s.add_runtime_dependency 'couchbase', '~> 1.2.0.dp'
19
+ s.add_runtime_dependency 'couchbase', '~> 1.3.0'
20
20
 
21
21
  s.add_development_dependency 'rake'
22
22
  s.add_development_dependency 'minitest'
23
+ s.add_development_dependency 'activesupport'
23
24
  end
@@ -19,5 +19,5 @@ require 'couchbase/model'
19
19
 
20
20
  # If we are using Rails then we will include the Couchbase railtie.
21
21
  if defined?(Rails)
22
- require "couchbase/railtie"
22
+ require 'couchbase/railtie'
23
23
  end
@@ -25,10 +25,10 @@ require 'couchbase/model/configuration'
25
25
  unless Object.respond_to?(:singleton_class)
26
26
  require 'couchbase/model/ext/singleton_class'
27
27
  end
28
- unless "".respond_to?(:constantize)
28
+ unless ''.respond_to?(:constantize)
29
29
  require 'couchbase/model/ext/constantize'
30
30
  end
31
- unless "".respond_to?(:camelize)
31
+ unless ''.respond_to?(:camelize)
32
32
  require 'couchbase/model/ext/camelize'
33
33
  end
34
34
 
@@ -43,9 +43,9 @@ module Couchbase
43
43
  def initialize(record)
44
44
  @record = record
45
45
  if @record.errors
46
- super(@record.errors.full_messages.join(", "))
46
+ super(@record.errors.full_messages.join(', '))
47
47
  else
48
- super("Record invalid")
48
+ super('Record invalid')
49
49
  end
50
50
  end
51
51
  end
@@ -221,7 +221,7 @@ module Couchbase
221
221
  # +by_session_id` and `total_views`.
222
222
  def self.ensure_design_document!
223
223
  unless Configuration.design_documents_paths
224
- raise "Configuration.design_documents_path must be directory"
224
+ raise 'Configuration.design_documents_path must be directory'
225
225
  end
226
226
 
227
227
  doc = {'_id' => "_design/#{design_document}", 'views' => {}}
@@ -351,7 +351,7 @@ module Couchbase
351
351
  end
352
352
  is_spatial = options.delete(:spatial)
353
353
  names.each do |name|
354
- path = "_design/%s/_%s/%s" % [design_document, is_spatial ? "spatial" : "view", name]
354
+ path = '_design/%s/_%s/%s' % [design_document, is_spatial ? 'spatial' : 'view', name]
355
355
  views[name] = lambda do |*params|
356
356
  params = options.merge(params.first || {})
357
357
  View.new(bucket, path, params)
@@ -389,40 +389,58 @@ module Couchbase
389
389
  end
390
390
  end
391
391
 
392
+ class << self
393
+ def _find(quiet, *ids)
394
+ wants_array = ids.first.kind_of?(Array)
395
+ ids = ids.flatten.compact.uniq
396
+ unless ids.empty?
397
+ res = bucket.get(ids, :quiet => quiet, :extended => true).map do |id, (obj, flags, cas)|
398
+ obj = {:raw => obj} unless obj.is_a?(Hash)
399
+ new({:id => id, :meta => {'flags' => flags, 'cas' => cas}}.merge(obj))
400
+ end
401
+ wants_array ? res : res.first
402
+ end
403
+ end
404
+
405
+ private :_find
406
+ end
407
+
392
408
  # Find the model using +id+ attribute
393
409
  #
394
410
  # @since 0.0.1
395
411
  #
396
- # @param [String, Symbol] id model identificator
397
- # @return [Couchbase::Model] an instance of the model
412
+ # @param [String, Symbol, Array] id model identificator(s)
413
+ # @return [Couchbase::Model, Array] an instance of the model, or an array of instances
398
414
  # @raise [Couchbase::Error::NotFound] when given key isn't exist
399
415
  #
400
416
  # @example Find model using +id+
401
417
  # post = Post.find('the-id')
402
- def self.find(id)
403
- if id && (res = bucket.get(id, :quiet => false, :extended => true))
404
- obj, flags, cas = res
405
- obj = {:raw => obj} unless obj.is_a?(Hash)
406
- new({:id => id, :meta => {'flags' => flags, 'cas' => cas}}.merge(obj))
407
- end
418
+ #
419
+ # @example Find multiple models using +id+
420
+ # post = Post.find('one', 'two')
421
+ def self.find(*id)
422
+ _find(false, *id)
408
423
  end
409
424
 
410
425
  # Find the model using +id+ attribute
411
426
  #
427
+ # Unlike {Couchbase::Model.find}, this method won't raise
428
+ # {Couchbase::Error::NotFound} error when key doesn't exist in the
429
+ # bucket
430
+ #
412
431
  # @since 0.1.0
413
432
  #
414
- # @param [String, Symbol] id model identificator
415
- # @return [Couchbase::Model, nil] an instance of the model or +nil+ if
433
+ # @param [String, Symbol] id model identificator(s)
434
+ # @return [Couchbase::Model, Array, nil] an instance of the model, an array
435
+ # of found instances of the model, or +nil+ if
416
436
  # given key isn't exist
417
437
  #
418
438
  # @example Find model using +id+
419
439
  # post = Post.find_by_id('the-id')
420
- def self.find_by_id(id)
421
- if id && (res = bucket.get(id, :quiet => true, :extended => true))
422
- obj, flags, cas = res
423
- obj = {:raw => obj} unless obj.is_a?(Hash)
424
- new({:id => id, :meta => {'flags' => flags, 'cas' => cas}}.merge(obj))
425
- end
440
+ # @example Find multiple models using +id+
441
+ # posts = Post.find_by_id(['the-id', 'the-id2'])
442
+ def self.find_by_id(*id)
443
+ _find(true, *id)
426
444
  end
427
445
 
428
446
  # Create the model with given attributes
@@ -586,7 +604,7 @@ module Couchbase
586
604
  # p = Post.find('hello-world')
587
605
  # p.delete
588
606
  def delete(options = {})
589
- raise Couchbase::Error::MissingId, "missing id attribute" unless @id
607
+ raise Couchbase::Error::MissingId, 'missing id attribute' unless @id
590
608
  model.bucket.delete(@id, options)
591
609
  @id = nil
592
610
  @meta = nil
@@ -704,7 +722,7 @@ module Couchbase
704
722
  # @raise [Error::MissingId] for records without +id+
705
723
  # attribute
706
724
  def reload
707
- raise Couchbase::Error::MissingId, "missing id attribute" unless @id
725
+ raise Couchbase::Error::MissingId, 'missing id attribute' unless @id
708
726
  attrs = model.find(@id).attributes
709
727
  update_attributes(attrs)
710
728
  self
@@ -779,15 +797,15 @@ module Couchbase
779
797
  # @since 0.0.1
780
798
  def inspect
781
799
  attrs = []
782
- attrs << ["key", @key.inspect] unless @key.nil?
783
- attrs << ["value", @value.inspect] unless @value.nil?
800
+ attrs << ['key', @key.inspect] unless @key.nil?
801
+ attrs << ['value', @value.inspect] unless @value.nil?
784
802
  model.attributes.map do |attr, default|
785
803
  val = read_attribute(attr)
786
804
  attrs << [attr.to_s, val.inspect] unless val.nil?
787
805
  end
788
806
  attrs.sort!
789
807
  attrs.unshift([:id, id]) unless new?
790
- sprintf("#<%s %s>", model, attrs.map{|a| a.join(": ")}.join(", "))
808
+ sprintf('#<%s %s>', model, attrs.map { |a| a.join(': ') }.join(', '))
791
809
  end
792
810
 
793
811
  def self.inspect
@@ -811,7 +829,7 @@ module Couchbase
811
829
 
812
830
  protected :attributes_with_values
813
831
 
814
- if defined?(::Rails)
832
+ if defined?(::ActiveModel)
815
833
  extend ActiveModel::Callbacks
816
834
  extend ActiveModel::Naming
817
835
  include ActiveModel::Conversion
@@ -839,7 +857,7 @@ module Couchbase
839
857
  def to_param
840
858
  keys = to_key
841
859
  if keys && !keys.empty?
842
- keys.join("-")
860
+ keys.join('-')
843
861
  end
844
862
  end
845
863
  end
@@ -43,7 +43,7 @@ module Couchbase
43
43
  # @param [Fixnum] seed seed for pseudorandom number generator.
44
44
  def initialize(seed = nil)
45
45
  seed ? srand(seed) : srand
46
- @prefix, _ = rand_bytes(13).unpack("H26")
46
+ @prefix, _ = rand_bytes(13).unpack('H26')
47
47
  @inc = rand(0xfff) + 1
48
48
  @lock = Mutex.new
49
49
  end
@@ -69,14 +69,14 @@ module Couchbase
69
69
  # @return [String, Array] single string value or array of strings. Where
70
70
  # each value represents 128-bit number written in hexadecimal format.
71
71
  def next(count = 1, algorithm = :sequential)
72
- raise ArgumentError, "count should be a positive number" unless count > 0
72
+ raise ArgumentError, 'count should be a positive number' unless count > 0
73
73
  uuids = case algorithm
74
74
  when :random
75
- rand_bytes(16 * count).unpack("H32" * count)
75
+ rand_bytes(16 * count).unpack('H32' * count)
76
76
  when :utc_random
77
77
  now = Time.now.utc
78
- prefix = "%014x" % [now.to_i * 1_000_000 + now.usec]
79
- rand_bytes(9 * count).unpack("H18" * count).map do |tail|
78
+ prefix = '%014x' % [now.to_i * 1_000_000 + now.usec]
79
+ rand_bytes(9 * count).unpack('H18' * count).map do |tail|
80
80
  "#{prefix}#{tail}"
81
81
  end
82
82
  when :sequential
@@ -92,16 +92,16 @@ module Couchbase
92
92
  def next_seq
93
93
  @lock.synchronize do
94
94
  if @inc >= 0xfff000
95
- @prefix, _ = rand_bytes(13).unpack("H26")
95
+ @prefix, _ = rand_bytes(13).unpack('H26')
96
96
  @inc = rand(0xfff) + 1
97
97
  end
98
98
  @inc += rand(0xfff) + 1
99
- "%s%06x" % [@prefix, @inc]
99
+ '%s%06x' % [@prefix, @inc]
100
100
  end
101
101
  end
102
102
 
103
103
  def rand_bytes(count)
104
- bytes = ""
104
+ bytes = ''
105
105
  count.times { bytes << rand(256) }
106
106
  bytes
107
107
  end
@@ -19,7 +19,7 @@ module Couchbase
19
19
 
20
20
  class Model
21
21
 
22
- VERSION = "0.5.2"
22
+ VERSION = '0.5.3'
23
23
 
24
24
  end
25
25
 
@@ -49,9 +49,9 @@ module Rails #:nodoc:
49
49
  # @return [Hash] rescued responses
50
50
  def self.rescue_responses
51
51
  {
52
- "Couchbase::Error::NotFound" => :not_found,
53
- "Couchbase::Error::NotStored" => :unprocessable_entity,
54
- "Couchbase::Error::RecordInvalid" => :unprocessable_entity
52
+ 'Couchbase::Error::NotFound' => :not_found,
53
+ 'Couchbase::Error::NotStored' => :unprocessable_entity,
54
+ 'Couchbase::Error::RecordInvalid' => :unprocessable_entity
55
55
  }
56
56
  end
57
57
 
@@ -85,8 +85,8 @@ module Rails #:nodoc:
85
85
  # <<: *common
86
86
  # bucket: example_development
87
87
  #
88
- initializer "couchbase.setup_connection" do
89
- config_file = Rails.root.join("config", "couchbase.yml")
88
+ initializer 'couchbase.setup_connection' do
89
+ config_file = Rails.root.join('config', 'couchbase.yml')
90
90
  if config_file.file? &&
91
91
  config = YAML.load(ERB.new(File.read(config_file)).result)[Rails.env]
92
92
  ::Couchbase.connection_options = config.with_indifferent_access
@@ -95,10 +95,10 @@ module Rails #:nodoc:
95
95
 
96
96
  # After initialization we will warn the user if we can't find a couchbase.yml and
97
97
  # alert to create one.
98
- initializer "couchbase.warn_configuration_missing" do
99
- unless ARGV.include?("couchbase:config")
98
+ initializer 'couchbase.warn_configuration_missing' do
99
+ unless ARGV.include?('couchbase:config')
100
100
  config.after_initialize do
101
- unless Rails.root.join("config", "couchbase.yml").file?
101
+ unless Rails.root.join('config', 'couchbase.yml').file?
102
102
  puts "\nCouchbase config not found. Create a config file at: config/couchbase.yml"
103
103
  puts "to generate one run: rails generate couchbase:config\n\n"
104
104
  end
@@ -107,13 +107,13 @@ module Rails #:nodoc:
107
107
  end
108
108
 
109
109
  # Check (and upgrade if needed) all design documents
110
- initializer "couchbase.upgrade_design_documents", :after =>"couchbase.setup_connection" do |app|
111
- ::Couchbase::Model::Configuration.design_documents_paths ||= app.config.paths["app/models"]
110
+ initializer 'couchbase.upgrade_design_documents', :after => 'couchbase.setup_connection' do |app|
111
+ ::Couchbase::Model::Configuration.design_documents_paths ||= app.config.paths['app/models']
112
112
  if config.couchbase.ensure_design_documents
113
113
  config.to_prepare do
114
- app.config.paths["app/models"].each do |path|
114
+ app.config.paths['app/models'].each do |path|
115
115
  Dir.glob("#{path}/**/*.rb").sort.each do |file|
116
- require_dependency(file.gsub("#{path}/" , "").gsub(".rb", ""))
116
+ require_dependency(file.gsub("#{path}/" , '').gsub('.rb', ''))
117
117
  end
118
118
  end
119
119
  begin
@@ -129,7 +129,7 @@ module Rails #:nodoc:
129
129
 
130
130
  # Set the proper error types for Rails. NotFound errors should be
131
131
  # 404s and not 500s, validation errors are 422s.
132
- initializer "couchbase.load_http_errors" do |app|
132
+ initializer 'couchbase.load_http_errors' do |app|
133
133
  config.after_initialize do
134
134
  unless config.action_dispatch.rescue_responses
135
135
  ActionDispatch::ShowExceptions.rescue_responses.update(Railtie.rescue_responses)
@@ -22,12 +22,12 @@ require 'rails/generators/couchbase_generator'
22
22
  module Couchbase
23
23
  module Generators
24
24
  class ConfigGenerator < Rails::Generators::Base
25
- desc "Creates a Couchbase configuration file at config/couchbase.yml"
25
+ desc 'Creates a Couchbase configuration file at config/couchbase.yml'
26
26
 
27
27
  argument :database_name, :type => :string, :optional => true
28
28
 
29
29
  def self.source_root
30
- @_couchbase_source_root ||= File.expand_path("../templates", __FILE__)
30
+ @_couchbase_source_root ||= File.expand_path('../templates', __FILE__)
31
31
  end
32
32
 
33
33
  def app_name
@@ -35,7 +35,7 @@ module Couchbase
35
35
  end
36
36
 
37
37
  def create_config_file
38
- template 'couchbase.yml', File.join('config', "couchbase.yml")
38
+ template 'couchbase.yml', File.join('config', 'couchbase.yml')
39
39
  end
40
40
 
41
41
  end
@@ -22,12 +22,12 @@ require 'rails/generators/couchbase_generator'
22
22
  module Couchbase
23
23
  module Generators
24
24
  class ViewGenerator < Rails::Generators::Base
25
- desc "Creates a Couchbase views skeletons for map/reduce functions"
25
+ desc 'Creates a Couchbase views skeletons for map/reduce functions'
26
26
 
27
27
  argument :model_name, :type => :string
28
28
  argument :view_name, :type => :string
29
29
 
30
- source_root File.expand_path("../templates", __FILE__)
30
+ source_root File.expand_path('../templates', __FILE__)
31
31
 
32
32
  def app_name
33
33
  Rails::Application.subclasses.first.parent.to_s.underscore
@@ -17,8 +17,8 @@
17
17
  # limitations under the License.
18
18
  #
19
19
 
20
- require "rails/generators/named_base"
21
- require "rails/generators/active_model"
20
+ require 'rails/generators/named_base'
21
+ require 'rails/generators/active_model'
22
22
 
23
23
  module Couchbase #:nodoc:
24
24
  module Generators #:nodoc:
@@ -34,12 +34,12 @@ class CouchbaseServer
34
34
  @port = @port.to_i
35
35
 
36
36
  if @host.nil? || @host.empty? || @port == 0
37
- raise ArgumentError, "Check COUCHBASE_SERVER variable. It should be hostname:port"
37
+ raise ArgumentError, 'Check COUCHBASE_SERVER variable. It should be hostname:port'
38
38
  end
39
39
 
40
40
  @config = Yajl::Parser.parse(open("http://#{@host}:#{@port}/pools/default"))
41
- @num_nodes = @config["nodes"].size
42
- @buckets_spec = params[:buckets_spec] || "default:" # "default:,protected:secret,cache::memcache"
41
+ @num_nodes = @config['nodes'].size
42
+ @buckets_spec = params[:buckets_spec] || 'default:' # "default:,protected:secret,cache::memcache"
43
43
  end
44
44
 
45
45
  def start
@@ -67,17 +67,17 @@ class CouchbaseMock
67
67
  end
68
68
 
69
69
  def initialize(params = {})
70
- @host = "127.0.0.1"
70
+ @host = '127.0.0.1'
71
71
  @port = 0
72
72
  @num_nodes = 10
73
73
  @num_vbuckets = 4096
74
- @buckets_spec = "default:" # "default:,protected:secret,cache::memcache"
74
+ @buckets_spec = 'default:' # "default:,protected:secret,cache::memcache"
75
75
  params.each do |key, value|
76
76
  send("#{key}=", value)
77
77
  end
78
78
  yield self if block_given?
79
79
  if @num_vbuckets < 1 || (@num_vbuckets & (@num_vbuckets - 1) != 0)
80
- raise ArgumentError, "Number of vbuckets should be a power of two and greater than zero"
80
+ raise ArgumentError, 'Number of vbuckets should be a power of two and greater than zero'
81
81
  end
82
82
  end
83
83
 
@@ -86,15 +86,15 @@ class CouchbaseMock
86
86
  @monitor.socket = TCPServer.new(nil, 0)
87
87
  @monitor.socket.listen(10)
88
88
  _, @monitor.port, _, _ = @monitor.socket.addr
89
- trap("CLD") do
90
- puts "CouchbaseMock.jar died unexpectedly during startup"
89
+ trap('CLD') do
90
+ puts 'CouchbaseMock.jar died unexpectedly during startup'
91
91
  exit(1)
92
92
  end
93
93
  @monitor.pid = fork
94
94
  if @monitor.pid.nil?
95
95
  rc = exec(command_line("--harakiri-monitor=:#{@monitor.port}"))
96
96
  else
97
- trap("CLD", "SIG_DFL")
97
+ trap('CLD', 'SIG_DFL')
98
98
  @monitor.client, _ = @monitor.socket.accept
99
99
  @port = @monitor.client.recv(100).to_i
100
100
  end
@@ -103,15 +103,15 @@ class CouchbaseMock
103
103
  def stop
104
104
  @monitor.client.close
105
105
  @monitor.socket.close
106
- Process.kill("TERM", @monitor.pid)
106
+ Process.kill('TERM', @monitor.pid)
107
107
  Process.wait(@monitor.pid)
108
108
  end
109
109
 
110
- def failover_node(index, bucket = "default")
110
+ def failover_node(index, bucket = 'default')
111
111
  @monitor.client.send("failover,#{index},#{bucket}", 0)
112
112
  end
113
113
 
114
- def respawn_node(index, bucket = "default")
114
+ def respawn_node(index, bucket = 'default')
115
115
  @monitor.client.send("respawn,#{index},#{bucket}", 0)
116
116
  end
117
117
 
@@ -137,7 +137,7 @@ class MiniTest::Unit::TestCase
137
137
  mock = CouchbaseServer.new(params)
138
138
  if (params[:port] && mock.port != params[:port]) ||
139
139
  (params[:host] && mock.host != params[:host]) ||
140
- mock.buckets_spec != "default:"
140
+ mock.buckets_spec != 'default:'
141
141
  skip("Unable to configure real cluster. Requested config is: #{params.inspect}")
142
142
  end
143
143
  else
@@ -163,6 +163,6 @@ class MiniTest::Unit::TestCase
163
163
  end
164
164
 
165
165
  def uniq_id(*suffixes)
166
- [caller.first[/.*[` ](.*)'/, 1], suffixes].join("_")
166
+ [caller.first[/.*[` ](.*)'/, 1], suffixes].join('_')
167
167
  end
168
168
  end
@@ -21,7 +21,7 @@ class Post < Couchbase::Model
21
21
  attribute :title
22
22
  attribute :body
23
23
  attribute :author, :default => 'Anonymous'
24
- attribute :created_at, :default => lambda { Time.utc("2010-01-01") }
24
+ attribute :created_at, :default => lambda { Time.utc('2010-01-01') }
25
25
  end
26
26
 
27
27
  class ValidPost < Couchbase::Model
@@ -50,6 +50,10 @@ class Comments < Couchbase::Model
50
50
  attribute :comments, :default => []
51
51
  end
52
52
 
53
+ class User < Couchbase::Model
54
+ design_document :people
55
+ end
56
+
53
57
  class TestModel < MiniTest::Unit::TestCase
54
58
 
55
59
  def setup
@@ -64,80 +68,86 @@ class TestModel < MiniTest::Unit::TestCase
64
68
  stop_mock(@mock)
65
69
  end
66
70
 
71
+ def test_design_document
72
+ assert_equal 'people', User.design_document
73
+ assert_equal 'new_people', User.design_document('new_people')
74
+ assert_equal 'post', Post.design_document
75
+ end
76
+
67
77
  def test_it_supports_value_property
68
78
  doc = {
69
- "id" => "x",
70
- "key" => "x",
71
- "value" => "x",
72
- "doc" => {
73
- "value" => {"title" => "foo"}
79
+ 'id' => 'x',
80
+ 'key' => 'x',
81
+ 'value' => 'x',
82
+ 'doc' => {
83
+ 'value' => {'title' => 'foo'}
74
84
  }
75
85
  }
76
86
  post = Post.wrap(Post.bucket, doc)
77
- assert_equal "foo", post.title
87
+ assert_equal 'foo', post.title
78
88
  end
79
89
 
80
90
  def test_it_supports_json_property
81
91
  doc = {
82
- "id" => "x",
83
- "key" => "x",
84
- "value" => "x",
85
- "doc" => {
86
- "json" => {"title" => "foo"}
92
+ 'id' => 'x',
93
+ 'key' => 'x',
94
+ 'value' => 'x',
95
+ 'doc' => {
96
+ 'json' => {'title' => 'foo'}
87
97
  }
88
98
  }
89
99
  post = Post.wrap(Post.bucket, doc)
90
- assert_equal "foo", post.title
100
+ assert_equal 'foo', post.title
91
101
  end
92
102
 
93
103
  def test_assigns_attributes_from_the_hash
94
- post = Post.new(:title => "Hello, world")
95
- assert_equal "Hello, world", post.title
104
+ post = Post.new(:title => 'Hello, world')
105
+ assert_equal 'Hello, world', post.title
96
106
  refute post.body
97
107
  refute post.id
98
108
  end
99
109
 
100
110
  def test_uses_default_value_or_nil
101
- post = Post.new(:title => "Hello, world")
111
+ post = Post.new(:title => 'Hello, world')
102
112
  refute post.body
103
113
  assert_equal 'Anonymous', post.author
104
114
  assert_equal 'Anonymous', post.attributes[:author]
105
115
  end
106
116
 
107
117
  def test_allows_lambda_as_default_value
108
- post = Post.new(:title => "Hello, world")
109
- expected = Time.utc("2010-01-01")
118
+ post = Post.new(:title => 'Hello, world')
119
+ expected = Time.utc('2010-01-01')
110
120
  assert_equal expected, post.created_at
111
121
  assert_equal expected, post.attributes[:created_at]
112
122
  end
113
123
 
114
124
  def test_assings_id_and_saves_the_object
115
- post = Post.create(:title => "Hello, world")
125
+ post = Post.create(:title => 'Hello, world')
116
126
  assert post.id
117
127
  end
118
128
 
119
129
  def test_updates_attributes
120
- post = Post.create(:title => "Hello, world")
121
- post.update(:body => "This is my first example")
122
- assert_equal "This is my first example", post.body
130
+ post = Post.create(:title => 'Hello, world')
131
+ post.update(:body => 'This is my first example')
132
+ assert_equal 'This is my first example', post.body
123
133
  end
124
134
 
125
135
  def test_refreshes_the_attributes_with_reload_method
126
- orig = Post.create(:title => "Hello, world")
136
+ orig = Post.create(:title => 'Hello, world')
127
137
  double = Post.find(orig.id)
128
- double.update(:title => "Good bye, world")
138
+ double.update(:title => 'Good bye, world')
129
139
  orig.reload
130
- assert_equal "Good bye, world", orig.title
140
+ assert_equal 'Good bye, world', orig.title
131
141
  end
132
142
 
133
143
  def test_it_raises_not_found_exception
134
144
  assert_raises Couchbase::Error::NotFound do
135
- Post.find("missing_key")
145
+ Post.find('missing_key')
136
146
  end
137
147
  end
138
148
 
139
149
  def test_it_returns_nil_when_key_not_found
140
- refute Post.find_by_id("missing_key")
150
+ refute Post.find_by_id('missing_key')
141
151
  end
142
152
 
143
153
  def test_doesnt_raise_if_the_attribute_redefined
@@ -163,22 +173,22 @@ class TestModel < MiniTest::Unit::TestCase
163
173
  end
164
174
 
165
175
  def test_allows_arbitrary_ids
166
- Post.create(:id => uniq_id, :title => "Foo")
167
- assert_equal "Foo", Post.find(uniq_id).title
176
+ Post.create(:id => uniq_id, :title => 'Foo')
177
+ assert_equal 'Foo', Post.find(uniq_id).title
168
178
  end
169
179
 
170
180
  def test_returns_an_instance_of_post
171
181
  Post.bucket.set(uniq_id, {:title => 'foo'})
172
182
  assert Post.find(uniq_id).kind_of?(Post)
173
183
  assert_equal uniq_id, Post.find(uniq_id).id
174
- assert_equal "foo", Post.find(uniq_id).title
184
+ assert_equal 'foo', Post.find(uniq_id).title
175
185
  end
176
186
 
177
187
  def test_changes_its_attributes
178
- post = Post.create(:title => "Hello, world")
179
- post.title = "Good bye, world"
188
+ post = Post.create(:title => 'Hello, world')
189
+ post.title = 'Good bye, world'
180
190
  post.save.reload
181
- assert_equal "Good bye, world", post.title
191
+ assert_equal 'Good bye, world', post.title
182
192
  end
183
193
 
184
194
  def test_assings_a_new_id_to_each_record
@@ -199,7 +209,7 @@ class TestModel < MiniTest::Unit::TestCase
199
209
  end
200
210
 
201
211
  def test_fails_to_delete_model_without_id
202
- post = Post.new(:title => "Hello")
212
+ post = Post.new(:title => 'Hello')
203
213
  refute post.id
204
214
  assert_raises Couchbase::Error::MissingId do
205
215
  post.delete
@@ -207,38 +217,38 @@ class TestModel < MiniTest::Unit::TestCase
207
217
  end
208
218
 
209
219
  def test_belongs_to_assoc
210
- brewery = Brewery.create(:name => "Anheuser-Busch")
220
+ brewery = Brewery.create(:name => 'Anheuser-Busch')
211
221
  assert_includes Beer.attributes.keys, :brewery_id
212
- beer = Beer.create(:name => "Budweiser", :brewery_id => brewery.id)
222
+ beer = Beer.create(:name => 'Budweiser', :brewery_id => brewery.id)
213
223
  assert_respond_to beer, :brewery
214
224
  assoc = beer.brewery
215
225
  assert_instance_of Brewery, assoc
216
- assert_equal "Anheuser-Busch", assoc.name
226
+ assert_equal 'Anheuser-Busch', assoc.name
217
227
  end
218
228
 
219
229
  def test_to_key
220
- assert_equal ["the-id"], Post.new(:id => "the-id").to_key
221
- assert_equal ["the-key"], Post.new(:key => "the-key").to_key
230
+ assert_equal ['the-id'], Post.new(:id => 'the-id').to_key
231
+ assert_equal ['the-key'], Post.new(:key => 'the-key').to_key
222
232
  end
223
233
 
224
234
  def test_to_param
225
- assert_equal "the-id", Post.new(:id => "the-id").to_param
226
- assert_equal "the-key", Post.new(:key => ["the", "key"]).to_param
235
+ assert_equal 'the-id', Post.new(:id => 'the-id').to_param
236
+ assert_equal 'the-key', Post.new(:key => ['the', 'key']).to_param
227
237
  end
228
238
 
229
239
  def test_as_json
230
240
  require 'active_support/json/encoding'
231
241
 
232
242
  response = {'id' => 'the-id'}
233
- assert_equal response, Post.new(:id => "the-id").as_json
243
+ assert_equal response, Post.new(:id => 'the-id').as_json
234
244
 
235
245
  response = {}
236
- assert_equal response, Post.new(:id => "the-id").as_json(:except => :id)
246
+ assert_equal response, Post.new(:id => 'the-id').as_json(:except => :id)
237
247
  end
238
248
 
239
249
  def test_validation
240
250
  post = ValidPost.create(:title => 'Hello, World!')
241
- assert post.valid?, "post with title should be valid"
251
+ assert post.valid?, 'post with title should be valid'
242
252
  post.title = nil
243
253
  refute post.save
244
254
  assert_raises(Couchbase::Error::RecordInvalid) do
@@ -261,4 +271,32 @@ class TestModel < MiniTest::Unit::TestCase
261
271
  assert_equal Couchbase::Model, Comments.couchbase_ancestor
262
272
  end
263
273
 
274
+ def test_returns_multiple_instances_of_post
275
+ Post.create(:id => uniq_id('first'), :title => 'foo')
276
+ Post.create(:id => uniq_id('second'), :title => 'bar')
277
+
278
+ results = Post.find([uniq_id('first'), uniq_id('second')])
279
+ assert results.kind_of?(Array)
280
+ assert results.size == 2
281
+ assert results.detect { |post| post.id == uniq_id('first') }.title == 'foo'
282
+ assert results.detect { |post| post.id == uniq_id('second') }.title == 'bar'
283
+ end
284
+
285
+ def test_returns_array_for_array_of_ids
286
+ Post.create(:id => uniq_id('first'), :title => 'foo')
287
+
288
+ results = Post.find([uniq_id('first')])
289
+ assert results.kind_of?(Array)
290
+ assert results.size == 1
291
+ assert results[0].title == 'foo'
292
+ end
293
+
294
+ def test_returns_array_for_array_of_ids_using_find_by_id
295
+ Post.create(:id => uniq_id('first'), :title => 'foo')
296
+
297
+ results = Post.find_by_id([uniq_id('first')])
298
+ assert results.kind_of?(Array)
299
+ assert results.size == 1
300
+ assert results[0].title == 'foo'
301
+ end
264
302
  end
metadata CHANGED
@@ -1,70 +1,90 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: couchbase-model
3
- version: !ruby/object:Gem::Version
4
- version: 0.5.2
3
+ version: !ruby/object:Gem::Version
4
+ hash: 13
5
5
  prerelease:
6
+ segments:
7
+ - 0
8
+ - 5
9
+ - 3
10
+ version: 0.5.3
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Couchbase
9
14
  autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
- date: 2013-02-25 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: couchbase
16
- requirement: !ruby/object:Gem::Requirement
17
+
18
+ date: 2013-06-06 00:00:00 +03:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ type: :runtime
23
+ requirement: &id001 !ruby/object:Gem::Requirement
17
24
  none: false
18
- requirements:
25
+ requirements:
19
26
  - - ~>
20
- - !ruby/object:Gem::Version
21
- version: 1.2.0.dp
22
- type: :runtime
27
+ - !ruby/object:Gem::Version
28
+ hash: 27
29
+ segments:
30
+ - 1
31
+ - 3
32
+ - 0
33
+ version: 1.3.0
34
+ name: couchbase
35
+ version_requirements: *id001
23
36
  prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
37
+ - !ruby/object:Gem::Dependency
38
+ type: :development
39
+ requirement: &id002 !ruby/object:Gem::Requirement
25
40
  none: false
26
- requirements:
27
- - - ~>
28
- - !ruby/object:Gem::Version
29
- version: 1.2.0.dp
30
- - !ruby/object:Gem::Dependency
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 3
45
+ segments:
46
+ - 0
47
+ version: "0"
31
48
  name: rake
32
- requirement: !ruby/object:Gem::Requirement
33
- none: false
34
- requirements:
35
- - - ! '>='
36
- - !ruby/object:Gem::Version
37
- version: '0'
38
- type: :development
49
+ version_requirements: *id002
39
50
  prerelease: false
40
- version_requirements: !ruby/object:Gem::Requirement
51
+ - !ruby/object:Gem::Dependency
52
+ type: :development
53
+ requirement: &id003 !ruby/object:Gem::Requirement
41
54
  none: false
42
- requirements:
43
- - - ! '>='
44
- - !ruby/object:Gem::Version
45
- version: '0'
46
- - !ruby/object:Gem::Dependency
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
47
62
  name: minitest
48
- requirement: !ruby/object:Gem::Requirement
49
- none: false
50
- requirements:
51
- - - ! '>='
52
- - !ruby/object:Gem::Version
53
- version: '0'
54
- type: :development
63
+ version_requirements: *id003
55
64
  prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
65
+ - !ruby/object:Gem::Dependency
66
+ type: :development
67
+ requirement: &id004 !ruby/object:Gem::Requirement
57
68
  none: false
58
- requirements:
59
- - - ! '>='
60
- - !ruby/object:Gem::Version
61
- version: '0'
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 3
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ name: activesupport
77
+ version_requirements: *id004
78
+ prerelease: false
62
79
  description: ORM-like interface allows you to persist your models to Couchbase
63
80
  email: support@couchbase.com
64
81
  executables: []
82
+
65
83
  extensions: []
84
+
66
85
  extra_rdoc_files: []
67
- files:
86
+
87
+ files:
68
88
  - .gitignore
69
89
  - .travis.yml
70
90
  - .yardopts
@@ -96,28 +116,39 @@ files:
96
116
  - test/test_model.rb
97
117
  - test/test_model_rails_integration.rb
98
118
  - test/test_uuid.rb
119
+ has_rdoc: true
99
120
  homepage: https://github.com/couchbase/couchbase-ruby-model
100
121
  licenses: []
122
+
101
123
  post_install_message:
102
124
  rdoc_options: []
103
- require_paths:
125
+
126
+ require_paths:
104
127
  - lib
105
- required_ruby_version: !ruby/object:Gem::Requirement
128
+ required_ruby_version: !ruby/object:Gem::Requirement
106
129
  none: false
107
- requirements:
108
- - - ! '>='
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- required_rubygems_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ hash: 3
134
+ segments:
135
+ - 0
136
+ version: "0"
137
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
138
  none: false
113
- requirements:
114
- - - ! '>='
115
- - !ruby/object:Gem::Version
116
- version: '0'
139
+ requirements:
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ hash: 3
143
+ segments:
144
+ - 0
145
+ version: "0"
117
146
  requirements: []
147
+
118
148
  rubyforge_project:
119
- rubygems_version: 1.8.23
149
+ rubygems_version: 1.6.2
120
150
  signing_key:
121
151
  specification_version: 3
122
152
  summary: Declarative interface to Couchbase
123
153
  test_files: []
154
+