couchbase-model 0.5.2 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+