dolly 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Rakefile +11 -0
- data/lib/dolly.rb +51 -0
- data/lib/dolly/collection.rb +57 -0
- data/lib/dolly/connection.rb +15 -0
- data/lib/dolly/document.rb +114 -0
- data/lib/dolly/property.rb +67 -0
- data/lib/dolly/representations/collection_representation.rb +15 -0
- data/lib/dolly/representations/document_representation.rb +19 -0
- data/lib/dolly/request.rb +58 -0
- data/lib/dolly/version.rb +3 -0
- data/lib/exceptions/dolly.rb +12 -0
- data/test/dolly_test.rb +147 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +27 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/couchdb.yml +15 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +29 -0
- data/test/dummy/config/environments/production.rb +80 -0
- data/test/dummy/config/environments/test.rb +36 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +12 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +56 -0
- data/test/dummy/lib/couch_rest_adapter/railtie.rb +10 -0
- data/test/dummy/log/test.log +12660 -0
- data/test/dummy/public/404.html +58 -0
- data/test/dummy/public/422.html +58 -0
- data/test/dummy/public/500.html +57 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/factories/factories.rb +8 -0
- data/test/test_helper.rb +37 -0
- metadata +239 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ea68df6004ba83c19215952ce9a3ce9e19169ec3
|
4
|
+
data.tar.gz: 835ecc53373d834ff7a8c05173200911490d7e4e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 40468de07bee1d6412e8dcae7b96f06d85ab9a7c8e1c7a41158a648f922cbb08b0b9c7ac3e54b30bf98a23647597f30d1c603dafabe784db61997323f5e12a9c
|
7
|
+
data.tar.gz: 30ddf8c41e68c48645f899d145aa439f6c4bde64218f82e048ba3af8aa85dc614fe7c18eeda6973faee88345cea4932c1ad07b4d4671c068d71c5416a4aa7f18
|
data/Rakefile
ADDED
data/lib/dolly.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require "dolly/version"
|
2
|
+
require "dolly/document"
|
3
|
+
require "dolly/property"
|
4
|
+
|
5
|
+
module Dolly
|
6
|
+
|
7
|
+
class Base
|
8
|
+
include Dolly::Document
|
9
|
+
attr_accessor :rows, :doc, :key
|
10
|
+
|
11
|
+
def rows= col
|
12
|
+
col.each{ |r| @doc = r['doc'] }
|
13
|
+
_properties.each do |p|
|
14
|
+
self.send "#{p.name}=", doc[p.name]
|
15
|
+
end
|
16
|
+
@rows = col
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.property *ary
|
20
|
+
options = ary.pop if ary.last.kind_of? Hash
|
21
|
+
options ||= {}
|
22
|
+
@properties ||= []
|
23
|
+
|
24
|
+
@properties += ary.map do |name|
|
25
|
+
options.merge!({name: name})
|
26
|
+
property = Property.new(options)
|
27
|
+
|
28
|
+
define_method(name) do
|
29
|
+
property.value = @doc[name.to_s]
|
30
|
+
property.value
|
31
|
+
end
|
32
|
+
|
33
|
+
define_method("#{name}=") do |val|
|
34
|
+
@doc ||={}
|
35
|
+
@doc[name.to_s] = val
|
36
|
+
end
|
37
|
+
|
38
|
+
define_method(:"#{name}?") { send name } if property.boolean?
|
39
|
+
define_method("[]") {|n| send n.to_sym}
|
40
|
+
|
41
|
+
property
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
def _properties
|
47
|
+
self.class.properties
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'dolly/representations/collection_representation'
|
2
|
+
|
3
|
+
module Dolly
|
4
|
+
class Collection
|
5
|
+
extend Forwardable
|
6
|
+
attr_accessor :rows
|
7
|
+
attr_writer :json, :docs_class
|
8
|
+
|
9
|
+
def_delegators :@set, :clear, :empty?, :length, :+, :-
|
10
|
+
|
11
|
+
def initialize str, docs_class
|
12
|
+
@set = Set.new
|
13
|
+
@docs_class = docs_class
|
14
|
+
@json = str
|
15
|
+
end
|
16
|
+
|
17
|
+
def map &block
|
18
|
+
load if empty?
|
19
|
+
@set.collect &block
|
20
|
+
end
|
21
|
+
|
22
|
+
def each &block
|
23
|
+
load if empty?
|
24
|
+
@set.each &block
|
25
|
+
#TODO: returning nil to avoid extra time serializing set.
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_a
|
30
|
+
load if empty?
|
31
|
+
@set.to_a
|
32
|
+
end
|
33
|
+
|
34
|
+
def count
|
35
|
+
load if empty?
|
36
|
+
length
|
37
|
+
end
|
38
|
+
|
39
|
+
def load
|
40
|
+
@set = self.extend(representation).from_json(json).rows
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
def representation
|
45
|
+
Representations::CollectionRepresentation.config(docs_class)
|
46
|
+
end
|
47
|
+
|
48
|
+
def docs_class
|
49
|
+
@docs_class
|
50
|
+
end
|
51
|
+
|
52
|
+
def json
|
53
|
+
@json
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require "active_model/naming"
|
2
|
+
require "dolly/connection"
|
3
|
+
require "dolly/collection"
|
4
|
+
require "dolly/representations/document_representation"
|
5
|
+
require "dolly/representations/collection_representation"
|
6
|
+
require "exceptions/dolly"
|
7
|
+
|
8
|
+
module Dolly
|
9
|
+
module Document
|
10
|
+
|
11
|
+
def id
|
12
|
+
doc['_id']
|
13
|
+
end
|
14
|
+
|
15
|
+
def rev
|
16
|
+
doc['_rev']
|
17
|
+
end
|
18
|
+
|
19
|
+
def save
|
20
|
+
response = database.put(id_as_resource, self.doc.to_json)
|
21
|
+
obj = JSON::parse response.parsed_response
|
22
|
+
doc['_rev'] = obj['rev'] if obj['rev']
|
23
|
+
obj['ok']
|
24
|
+
end
|
25
|
+
|
26
|
+
def save!
|
27
|
+
#TODO: decide how to handle validations...
|
28
|
+
save
|
29
|
+
end
|
30
|
+
|
31
|
+
def from_json string
|
32
|
+
self.class.new.extend(representation).from_json( string )
|
33
|
+
end
|
34
|
+
|
35
|
+
def database
|
36
|
+
self.class.database
|
37
|
+
end
|
38
|
+
|
39
|
+
def id_as_resource
|
40
|
+
CGI::escape id
|
41
|
+
end
|
42
|
+
|
43
|
+
def representation
|
44
|
+
Representations::DocumentRepresentation.config(self.class.properties)
|
45
|
+
end
|
46
|
+
|
47
|
+
module ClassMethods
|
48
|
+
include ActiveModel::Naming
|
49
|
+
include Dolly::Connection
|
50
|
+
attr_accessor :properties
|
51
|
+
|
52
|
+
DESIGN_DOC = "dolly"
|
53
|
+
|
54
|
+
def find *ids
|
55
|
+
response = default_view(keys: ids.map{|id| namespace(id)}).parsed_response
|
56
|
+
ids.count > 1 ? Collection.new(response, name.constantize) : self.new.from_json(response)
|
57
|
+
rescue NoMethodError => err
|
58
|
+
if err.message == "undefined method `[]' for nil:NilClass"
|
59
|
+
raise Dolly::ResourceNotFound
|
60
|
+
else
|
61
|
+
raise
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def all
|
66
|
+
Collection.new default_view.parsed_response, name.constantize
|
67
|
+
end
|
68
|
+
|
69
|
+
def default_view options = {}
|
70
|
+
view default_doc, options
|
71
|
+
end
|
72
|
+
|
73
|
+
def view doc, options = {}
|
74
|
+
options.merge! include_docs: true
|
75
|
+
database.get doc, options
|
76
|
+
end
|
77
|
+
|
78
|
+
def default_doc
|
79
|
+
"#{design_doc}/_view/#{name_paramitized}"
|
80
|
+
end
|
81
|
+
|
82
|
+
def design_doc
|
83
|
+
"_design/#{@@design_doc || DESIGN_DOC}"
|
84
|
+
end
|
85
|
+
|
86
|
+
def set_design_doc value
|
87
|
+
@@design_doc = value
|
88
|
+
end
|
89
|
+
|
90
|
+
def name_paramitized
|
91
|
+
model_name.param_key
|
92
|
+
end
|
93
|
+
|
94
|
+
def namespace id
|
95
|
+
return id if id =~ /^#{name_paramitized}/
|
96
|
+
"#{name_paramitized}/#{id}"
|
97
|
+
end
|
98
|
+
|
99
|
+
def timestamps!
|
100
|
+
%i/created_at updated_at/.each do |method|
|
101
|
+
define_method(method){ @doc[method.to_s] ||= DateTime.now }
|
102
|
+
define_method(:"[]"){|m| self.send(m.to_sym) }
|
103
|
+
define_method(:"[]="){|m, v| self.send(:"#{m}=", v) }
|
104
|
+
define_method(:"#{method}="){|val| @doc[method.to_s] = val }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.included(base)
|
111
|
+
base.extend ClassMethods
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Dolly
|
2
|
+
class Property
|
3
|
+
attr_writer :value
|
4
|
+
attr_accessor :name
|
5
|
+
|
6
|
+
def initialize opts = {}
|
7
|
+
@class_name = opts.delete(:class_name) if opts.present?
|
8
|
+
@name = opts.delete(:name).to_s
|
9
|
+
@default = opts.delete(:default)
|
10
|
+
warn 'There are some unprocesed options' if opts.present?
|
11
|
+
end
|
12
|
+
|
13
|
+
def value
|
14
|
+
return @default if @value.nil?
|
15
|
+
return @value unless self_klass
|
16
|
+
|
17
|
+
klass_sym = :"#{self_klass.name.underscore}_#{__method__}"
|
18
|
+
|
19
|
+
return self_klass.new @value unless self.respond_to?(klass_sym)
|
20
|
+
|
21
|
+
self.send klass_sym
|
22
|
+
end
|
23
|
+
|
24
|
+
def array_value
|
25
|
+
@value.to_a
|
26
|
+
end
|
27
|
+
|
28
|
+
def hash_value
|
29
|
+
@value.to_h
|
30
|
+
end
|
31
|
+
|
32
|
+
def string_value
|
33
|
+
@value.to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
def integer_value
|
37
|
+
@value.to_i
|
38
|
+
end
|
39
|
+
|
40
|
+
def float_value
|
41
|
+
@value.to_f
|
42
|
+
end
|
43
|
+
|
44
|
+
def true_class_value
|
45
|
+
truthy_value?
|
46
|
+
end
|
47
|
+
|
48
|
+
def false_class_value
|
49
|
+
truthy_value?
|
50
|
+
end
|
51
|
+
|
52
|
+
def boolean?
|
53
|
+
self_klass == TrueClass || self_klass == FalseClass
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
def truthy_value?
|
58
|
+
@value =~ /true/ || @value === true
|
59
|
+
end
|
60
|
+
|
61
|
+
def self_klass
|
62
|
+
return unless @class_name
|
63
|
+
@class_name.is_a?(Class)? @class_name : @class_name.constantize
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'representable/json'
|
2
|
+
|
3
|
+
module Dolly
|
4
|
+
module Representations
|
5
|
+
module CollectionRepresentation
|
6
|
+
include Representable::JSON
|
7
|
+
|
8
|
+
def self.config docs_class
|
9
|
+
self.collection :rows, extend: DocumentRepresentation, class: docs_class
|
10
|
+
self
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'representable/json'
|
2
|
+
|
3
|
+
module Dolly
|
4
|
+
module Representations
|
5
|
+
module DocumentRepresentation
|
6
|
+
include Representable::JSON
|
7
|
+
|
8
|
+
property :rows
|
9
|
+
property :doc
|
10
|
+
|
11
|
+
def self.config properties
|
12
|
+
properties.each do |p|
|
13
|
+
self.property p.name
|
14
|
+
end
|
15
|
+
self
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "httparty"
|
2
|
+
|
3
|
+
module Dolly
|
4
|
+
|
5
|
+
class Request
|
6
|
+
include HTTParty
|
7
|
+
DEFAULT_HOST = 'localhost'
|
8
|
+
DEFAULT_PORT = '5984'
|
9
|
+
|
10
|
+
attr_accessor :database_name, :host, :port
|
11
|
+
|
12
|
+
def initialize options = {}
|
13
|
+
@host = options[:host] || DEFAULT_HOST
|
14
|
+
@port = options[:port] || DEFAULT_PORT
|
15
|
+
@database_name = options[:database_name]
|
16
|
+
|
17
|
+
self.class.base_uri "#{protocol}://#{host}:#{port}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def get resource, data
|
21
|
+
request :get, resource, {query: values_to_json(data)}
|
22
|
+
end
|
23
|
+
|
24
|
+
def put resource, data
|
25
|
+
request :put, resource, {body: data}
|
26
|
+
end
|
27
|
+
|
28
|
+
def delete resource
|
29
|
+
request :delete, resource, {}
|
30
|
+
end
|
31
|
+
|
32
|
+
def protocol
|
33
|
+
@protocol || 'http'
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def values_to_json hash
|
38
|
+
hash.reduce({}){|h, v| h[v.first] = v.last.to_json; h}
|
39
|
+
end
|
40
|
+
|
41
|
+
def full_path resource
|
42
|
+
"/#{database_name}/#{resource}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def request method, resource, data = nil
|
46
|
+
headers = { 'Content-Type' => 'application/json' }
|
47
|
+
response = self.class.send method, full_path(resource), data.merge(headers: headers)
|
48
|
+
if response.code == 404
|
49
|
+
raise Dolly::ResourceNotFound
|
50
|
+
elsif (500..600).include? response.code
|
51
|
+
raise Dolly::ServerError
|
52
|
+
else
|
53
|
+
response
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
data/test/dolly_test.rb
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class FooBar < Dolly::Base
|
4
|
+
database_name 'test'
|
5
|
+
set_design_doc 'test'
|
6
|
+
|
7
|
+
property :foo, :bar
|
8
|
+
property :with_default, default: 1
|
9
|
+
property :boolean, class_name: TrueClass, default: true
|
10
|
+
|
11
|
+
timestamps!
|
12
|
+
end
|
13
|
+
|
14
|
+
class DollyTest < ActiveSupport::TestCase
|
15
|
+
|
16
|
+
def setup
|
17
|
+
data = {foo: 'Foo', bar: 'Bar', type: 'foo_bar'}
|
18
|
+
all_docs = [ {foo: 'Foo B', bar: 'Bar B', type: 'foo_bar'}, {foo: 'Foo A', bar: 'Bar A', type: 'foo_bar'}]
|
19
|
+
|
20
|
+
view_resp = build_view_response [data]
|
21
|
+
empty_resp = build_view_response []
|
22
|
+
@multi_resp = build_view_response all_docs
|
23
|
+
|
24
|
+
build_request ["foo_bar/1"], view_resp
|
25
|
+
build_request ["foo_bar/2"], empty_resp
|
26
|
+
build_request ["foo_bar/1","foo_bar/2"], @multi_resp
|
27
|
+
build_request [], @multi_resp
|
28
|
+
end
|
29
|
+
|
30
|
+
test 'with timestamps!' do
|
31
|
+
later = DateTime.new 1963, 1, 1
|
32
|
+
now = DateTime.now
|
33
|
+
DateTime.stubs(:now).returns(now)
|
34
|
+
foo = FooBar.find "1"
|
35
|
+
assert_equal now, foo.created_at
|
36
|
+
assert_equal now, foo['created_at']
|
37
|
+
assert_equal now, foo.updated_at
|
38
|
+
assert foo.updated_at = later
|
39
|
+
assert_equal later, foo.updated_at
|
40
|
+
assert foo['created_at'] = later
|
41
|
+
assert_equal later, foo['created_at']
|
42
|
+
assert_equal foo['created_at'], foo.created_at
|
43
|
+
end
|
44
|
+
|
45
|
+
test 'empty find should raise error' do
|
46
|
+
assert_raise Dolly::ResourceNotFound do
|
47
|
+
FakeWeb.register_uri :get, "http://localhost:5984/test/_design/test/_view/foo_bar?keys=%5B%5D&include_docs=true", :status => ["404", "Not Found"]
|
48
|
+
foo = FooBar.find
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
test 'error on server raises Dolly::ServerError' do
|
53
|
+
assert_raise Dolly::ServerError do
|
54
|
+
FakeWeb.register_uri :get, "http://localhost:5984/test/_design/test/_view/foo_bar?keys=%5B%5D&include_docs=true", :status => ["500", "Error"]
|
55
|
+
foo = FooBar.find
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
test 'will have object with boolean? method' do
|
60
|
+
foo = FooBar.find "1"
|
61
|
+
assert_equal true, foo.boolean?
|
62
|
+
foo.boolean = false
|
63
|
+
assert_equal false, foo['boolean']
|
64
|
+
assert_equal false, foo.boolean?
|
65
|
+
end
|
66
|
+
|
67
|
+
test 'find will get a FooBar document' do
|
68
|
+
foo = FooBar.find "1"
|
69
|
+
assert_equal true, foo.kind_of?(FooBar)
|
70
|
+
end
|
71
|
+
|
72
|
+
test 'will have key properties' do
|
73
|
+
foo = FooBar.find "1"
|
74
|
+
assert_equal 'Foo', foo['foo']
|
75
|
+
assert_equal 'Bar', foo['bar']
|
76
|
+
end
|
77
|
+
|
78
|
+
test 'will have only set properties' do
|
79
|
+
foo = FooBar.find "1"
|
80
|
+
assert_equal 'Foo', foo.foo
|
81
|
+
assert_equal 'Bar', foo.bar
|
82
|
+
assert_equal false, foo.respond_to?(:type)
|
83
|
+
end
|
84
|
+
|
85
|
+
test 'with default will return default value on nil' do
|
86
|
+
foo = FooBar.find "1"
|
87
|
+
assert_equal 1, foo.with_default
|
88
|
+
end
|
89
|
+
|
90
|
+
test 'default will be avoerwriten' do
|
91
|
+
foo = FooBar.find "1"
|
92
|
+
assert_equal 1, foo.with_default
|
93
|
+
assert foo.with_default = 30
|
94
|
+
assert_equal 30, foo.with_default
|
95
|
+
end
|
96
|
+
|
97
|
+
test 'getting not found document' do
|
98
|
+
assert_raise Dolly::ResourceNotFound do
|
99
|
+
missing = FooBar.find "2"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
test 'find with multiple ids will return Collection' do
|
104
|
+
many = FooBar.find "1", "2"
|
105
|
+
assert_equal true, many.kind_of?(Dolly::Collection)
|
106
|
+
end
|
107
|
+
|
108
|
+
test 'all will get 2 docs' do
|
109
|
+
all = FooBar.all
|
110
|
+
assert_equal 2, all.count
|
111
|
+
end
|
112
|
+
|
113
|
+
test 'all will get FooBar documents' do
|
114
|
+
all = FooBar.all
|
115
|
+
all.each{ |d| assert_equal true, d.kind_of?(FooBar) }
|
116
|
+
end
|
117
|
+
|
118
|
+
test 'multi response with right data' do
|
119
|
+
all = FooBar.all
|
120
|
+
ids = @multi_resp[:rows].map{|d| d[:id]}
|
121
|
+
foos = @multi_resp[:rows].map{|d| d[:doc][:foo]}
|
122
|
+
bars = @multi_resp[:rows].map{|d| d[:doc][:bar]}
|
123
|
+
all.each do |d|
|
124
|
+
assert foos.include?(d.foo)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
def build_view_response properties
|
130
|
+
rows = properties.map.with_index do |v, i|
|
131
|
+
{
|
132
|
+
id: "foo_bar/#{i}",
|
133
|
+
key: "foo_bar",
|
134
|
+
value: 1,
|
135
|
+
doc: {_id: "foo_bar/#{i}", _rev: SecureRandom.hex}.merge!(v)
|
136
|
+
}
|
137
|
+
end
|
138
|
+
{total_rows: properties.count, offset:0, rows: rows}
|
139
|
+
end
|
140
|
+
|
141
|
+
def build_request keys, body, view_name = 'foo_bar'
|
142
|
+
base_url = "http://localhost:5984/test/_design/test/_view/foo_bar"
|
143
|
+
query = "keys=#{CGI::escape keys.to_s.gsub(' ','')}&" unless keys.blank?
|
144
|
+
FakeWeb.register_uri :get, "#{base_url}?#{query.to_s}include_docs=true", body: body.to_json
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|