CloudSesame 0.6.4 → 0.6.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +5 -3
- data/.rubocop.yml +1158 -0
- data/.travis.yml +11 -0
- data/Gemfile.lock +28 -1
- data/Guardfile +6 -1
- data/README.md +6 -1
- data/cloud_sesame.gemspec +4 -2
- data/coverage/.last_run.json +5 -0
- data/coverage/.resultset.json +2423 -0
- data/coverage/.resultset.json.lock +0 -0
- data/lib/cloud_sesame.rb +4 -5
- data/lib/cloud_sesame/domain/base.rb +46 -33
- data/lib/cloud_sesame/domain/client_module/caching/base.rb +1 -1
- data/lib/cloud_sesame/query/ast/near.rb +1 -1
- data/lib/cloud_sesame/query/ast/operator.rb +1 -1
- data/lib/cloud_sesame/query/ast/range_value.rb +23 -30
- data/lib/cloud_sesame/query/ast/single_expression_operator.rb +1 -1
- data/lib/cloud_sesame/query/ast/value.rb +18 -4
- data/lib/cloud_sesame/query/domain/block.rb +2 -2
- data/lib/cloud_sesame/query/domain/literal.rb +1 -1
- data/lib/cloud_sesame/query/dsl/applied_filter_query.rb +21 -23
- data/lib/cloud_sesame/query/dsl/field_accessors.rb +8 -3
- data/lib/cloud_sesame/query/dsl/response_methods.rb +2 -2
- data/lib/cloud_sesame/query/dsl/scope_accessors.rb +1 -1
- data/lib/cloud_sesame/query/node/fuzziness.rb +11 -13
- data/lib/cloud_sesame/query/node/query.rb +9 -10
- data/lib/cloud_sesame/query/node/request.rb +2 -2
- data/lib/cloud_sesame/query/node/sloppiness.rb +23 -0
- data/spec/cloud_sesame/config/credential_spec.rb +76 -0
- data/spec/cloud_sesame/domain/base_spec.rb +274 -9
- data/spec/cloud_sesame/domain/client_spec.rb +0 -1
- data/spec/cloud_sesame/query/domain/block_spec.rb +0 -1
- data/spec/cloud_sesame/query/node/query_spec.rb +18 -7
- data/spec/cloud_sesame_spec.rb +10 -10
- data/spec/spec_helper.rb +3 -0
- metadata +38 -3
- data/lib/cloud_sesame/domain/context.rb +0 -39
@@ -3,6 +3,8 @@ module CloudSesame
|
|
3
3
|
module Node
|
4
4
|
class Fuzziness
|
5
5
|
|
6
|
+
EXCLUDING_TERMS = /^\-/
|
7
|
+
|
6
8
|
def initialize(&block)
|
7
9
|
|
8
10
|
# default fuzziness
|
@@ -10,7 +12,7 @@ module CloudSesame
|
|
10
12
|
@min_char_size = 6
|
11
13
|
@fuzzy_percent = 0.17
|
12
14
|
|
13
|
-
instance_eval
|
15
|
+
instance_eval(&block) if block_given?
|
14
16
|
end
|
15
17
|
|
16
18
|
def max_fuzziness(int)
|
@@ -25,32 +27,28 @@ module CloudSesame
|
|
25
27
|
@fuzzy_percent = float.to_f
|
26
28
|
end
|
27
29
|
|
28
|
-
def
|
29
|
-
|
30
|
+
def compile(string)
|
31
|
+
"(#{ each_word_in(string) { |word| fuzziness(word) }.compact.join('+') })"
|
30
32
|
end
|
31
33
|
|
32
34
|
private
|
33
35
|
|
34
|
-
def
|
35
|
-
string.split(' ').map
|
36
|
+
def each_word_in(string, &block)
|
37
|
+
string.split(' ').map(&block)
|
36
38
|
end
|
37
39
|
|
38
40
|
def fuzziness(word)
|
39
|
-
if word.length >= @min_char_size && !excluding_term?(word)
|
40
|
-
fuzziness = (
|
41
|
+
if (length = word.length) >= @min_char_size && !excluding_term?(word)
|
42
|
+
fuzziness = (length * @fuzzy_percent).round
|
41
43
|
fuzziness = [fuzziness, @max_fuzziness].min
|
42
|
-
"#{word}~#{fuzziness}"
|
44
|
+
"#{ word }~#{ fuzziness }"
|
43
45
|
else
|
44
46
|
word
|
45
47
|
end
|
46
48
|
end
|
47
49
|
|
48
|
-
def join_by_and(args = [])
|
49
|
-
(args = args.compact).size > 1 ? "(#{ args.join('+') })" : args[0]
|
50
|
-
end
|
51
|
-
|
52
50
|
def excluding_term?(word)
|
53
|
-
!!word
|
51
|
+
!!(EXCLUDING_TERMS =~ word)
|
54
52
|
end
|
55
53
|
|
56
54
|
end
|
@@ -10,24 +10,23 @@ module CloudSesame
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def compile
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
{ query: "(#{
|
14
|
+
query
|
15
|
+
})#{
|
16
|
+
'|' << fuzziness.compile(query) if fuzziness
|
17
|
+
}#{
|
18
|
+
'|' << sloppiness.compile(query) if sloppiness
|
19
|
+
}" }
|
17
20
|
end
|
18
21
|
|
19
22
|
private
|
20
23
|
|
21
24
|
def fuzziness
|
22
|
-
context[:fuzziness]
|
25
|
+
context[:fuzziness]
|
23
26
|
end
|
24
27
|
|
25
28
|
def sloppiness
|
26
|
-
context[:sloppiness]
|
27
|
-
end
|
28
|
-
|
29
|
-
def join_by_or(args = [])
|
30
|
-
(args = args.compact).size > 1 ? "(#{ args.join('|') })" : args[0]
|
29
|
+
context[:sloppiness]
|
31
30
|
end
|
32
31
|
|
33
32
|
end
|
@@ -51,8 +51,8 @@ module CloudSesame
|
|
51
51
|
page,
|
52
52
|
sort,
|
53
53
|
return_field
|
54
|
-
].each_with_object({}) do |node,
|
55
|
-
|
54
|
+
].each_with_object({}) do |node, object|
|
55
|
+
object.merge!(node.compile || {})
|
56
56
|
end
|
57
57
|
|
58
58
|
if compiled[:filter_query].empty?
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module CloudSesame
|
2
|
+
module Query
|
3
|
+
module Node
|
4
|
+
class Sloppiness
|
5
|
+
|
6
|
+
def initialize(value)
|
7
|
+
@value = value.to_i
|
8
|
+
end
|
9
|
+
|
10
|
+
def compile(string)
|
11
|
+
"\"#{ string }\"~#{ @value }" if more_than_one_word?(string)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def more_than_one_word?(string)
|
17
|
+
string.include?(' ')
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module CloudSesame
|
2
|
+
module Config
|
3
|
+
describe Credential do
|
4
|
+
|
5
|
+
describe '#initialize' do
|
6
|
+
it 'should accept access_key_id' do
|
7
|
+
credential = Credential.new(access_key_id: 123)
|
8
|
+
expect(credential.to_hash[:access_key_id]).to eq 123
|
9
|
+
end
|
10
|
+
it 'should accept access_key as an alias for access_key_id' do
|
11
|
+
credential = Credential.new(access_key: 123)
|
12
|
+
expect(credential.to_hash[:access_key_id]).to eq 123
|
13
|
+
end
|
14
|
+
it 'should accept secret_access_key' do
|
15
|
+
credential = Credential.new(secret_access_key: 'secret')
|
16
|
+
expect(credential.to_hash[:secret_access_key]).to eq 'secret'
|
17
|
+
end
|
18
|
+
it 'should accept secret_key as an alias for secret_access_key' do
|
19
|
+
credential = Credential.new(secret_key: 'secret')
|
20
|
+
expect(credential.to_hash[:secret_access_key]).to eq 'secret'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe 'access_key_id' do
|
25
|
+
context 'getter' do
|
26
|
+
subject { Credential.new(access_key: 123) }
|
27
|
+
it 'should be defined' do
|
28
|
+
expect(subject).to respond_to(:access_key_id)
|
29
|
+
expect(subject.access_key_id).to eq 123
|
30
|
+
end
|
31
|
+
it 'should have an alias getter defined' do
|
32
|
+
expect(subject).to respond_to(:access_key)
|
33
|
+
expect(subject.access_key).to eq 123
|
34
|
+
end
|
35
|
+
end
|
36
|
+
context 'writer' do
|
37
|
+
let(:attributes) { subject.instance_variable_get(:@attributes) }
|
38
|
+
it 'should be defined' do
|
39
|
+
expect(subject).to respond_to(:access_key_id=)
|
40
|
+
expect{ subject.access_key_id = 123 }.to change{ attributes[:access_key_id] }.from(nil).to(123)
|
41
|
+
end
|
42
|
+
it 'should have an alias writer defined' do
|
43
|
+
expect(subject).to respond_to(:access_key=)
|
44
|
+
expect{ subject.access_key = 123 }.to change{ attributes[:access_key_id] }.from(nil).to(123)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'secret_access_key' do
|
50
|
+
context 'getter' do
|
51
|
+
subject { Credential.new(secret_key: 123) }
|
52
|
+
it 'should be defined' do
|
53
|
+
expect(subject).to respond_to(:secret_access_key)
|
54
|
+
expect(subject.secret_access_key).to eq 123
|
55
|
+
end
|
56
|
+
it 'should have an alias getter defined' do
|
57
|
+
expect(subject).to respond_to(:secret_key)
|
58
|
+
expect(subject.secret_key).to eq 123
|
59
|
+
end
|
60
|
+
end
|
61
|
+
context 'writer' do
|
62
|
+
let(:attributes) { subject.instance_variable_get(:@attributes) }
|
63
|
+
it 'should be defined' do
|
64
|
+
expect(subject).to respond_to(:secret_access_key=)
|
65
|
+
expect{ subject.secret_access_key = 123 }.to change{ attributes[:secret_access_key] }.from(nil).to(123)
|
66
|
+
end
|
67
|
+
it 'should have an alias writer defined' do
|
68
|
+
expect(subject).to respond_to(:secret_key=)
|
69
|
+
expect{ subject.secret_key = 123 }.to change{ attributes[:secret_access_key] }.from(nil).to(123)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -1,25 +1,290 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
1
|
module CloudSesame
|
4
2
|
module Domain
|
5
3
|
describe Base do
|
6
4
|
|
7
|
-
|
8
|
-
|
5
|
+
class BaseSearchable; end
|
6
|
+
|
7
|
+
let(:searchable) { BaseSearchable }
|
8
|
+
subject { Base.new(searchable) }
|
9
9
|
|
10
|
-
|
11
|
-
it 'should
|
12
|
-
expect(subject.
|
10
|
+
shared_examples 'delegation to client' do |method|
|
11
|
+
it 'should be delegated to #client' do
|
12
|
+
expect(subject.client).to receive(method)
|
13
|
+
subject.send(method)
|
13
14
|
end
|
14
15
|
end
|
15
16
|
|
16
|
-
describe '#
|
17
|
+
describe '#config' do
|
18
|
+
it_behaves_like 'delegation to client', :config
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#caching_with' do
|
22
|
+
it_behaves_like 'delegation to client', :caching_with
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#builder' do
|
26
|
+
it 'should initialize an new builder each time' do
|
27
|
+
number = 2
|
28
|
+
expect(Query::Builder).to receive(:new).exactly(number).times.and_call_original
|
29
|
+
number.times { subject.builder }
|
30
|
+
end
|
31
|
+
it 'should receive the context from base when called' do
|
32
|
+
c = Context.new
|
33
|
+
expect(subject).to receive(:context).and_return(c)
|
34
|
+
subject.builder
|
35
|
+
end
|
36
|
+
it 'should receive the searchable form base when called' do
|
37
|
+
expect(subject).to receive(:searchable).and_return(searchable)
|
38
|
+
subject.builder
|
39
|
+
end
|
17
40
|
end
|
18
41
|
|
19
42
|
describe '#client' do
|
43
|
+
it 'should initialize and return a domain client with searchable' do
|
44
|
+
expect(Client).to receive(:new).with(searchable)
|
45
|
+
subject.client
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#context' do
|
50
|
+
it 'should initialize and return a context' do
|
51
|
+
expect(Context).to receive(:new)
|
52
|
+
subject.context
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#default_size' do
|
57
|
+
it 'should store the value to context page size' do
|
58
|
+
size = 99
|
59
|
+
subject.default_size size
|
60
|
+
expect(subject.context[:page][:size]).to eq(size)
|
61
|
+
end
|
62
|
+
it 'should convert value to integer' do
|
63
|
+
size = "99"
|
64
|
+
subject.default_size size
|
65
|
+
expect(subject.context[:page][:size]).to eq(size.to_i)
|
66
|
+
end
|
67
|
+
it 'should add page size to context' do
|
68
|
+
expect{ subject.default_size 99 }.to change{ subject.context[:page] }.from(nil).to(hash_including(size: 99))
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#define_sloppiness' do
|
73
|
+
it 'should create a sloppiness node' do
|
74
|
+
value = 3
|
75
|
+
expect(Query::Node::Sloppiness).to receive(:new).with(value)
|
76
|
+
subject.define_sloppiness(value)
|
77
|
+
end
|
78
|
+
it 'should add query sloppiness to context' do
|
79
|
+
expect{ subject.define_sloppiness 3 }.to change{ subject.context[:query] }.from(nil).to(hash_including(sloppiness: Query::Node::Sloppiness))
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe '#define_fuzziness' do
|
84
|
+
let(:block) { Proc.new {} }
|
85
|
+
it 'should create a fuzziness node' do
|
86
|
+
expect(Query::Node::Fuzziness).to receive(:new) { |&b|
|
87
|
+
expect(b).to eq block
|
88
|
+
}
|
89
|
+
subject.define_fuzziness(&block)
|
90
|
+
end
|
91
|
+
it 'should add query fuzziness to context' do
|
92
|
+
expect{ subject.define_fuzziness {} }.to change{ subject.context[:query] }.from(nil).to(hash_including(fuzziness: Query::Node::Fuzziness))
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe '#field' do
|
97
|
+
let(:field_name) { :name }
|
98
|
+
|
99
|
+
shared_examples 'and options :as is also passed' do
|
100
|
+
let(:real_name) { :text1 }
|
101
|
+
before { options[:as] = real_name }
|
102
|
+
it 'should use the real name as field name' do
|
103
|
+
subject.field field_name, options
|
104
|
+
expect(custom_options).to include(real_name)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'when options :query is passed in' do
|
109
|
+
let(:options) { { query: true } }
|
110
|
+
|
111
|
+
context 'and query is set to true' do
|
112
|
+
it 'should add query options for field' do
|
113
|
+
subject.field(field_name, options)
|
114
|
+
expect(subject.context[:query_options][:fields][field_name]).to eq({})
|
115
|
+
end
|
116
|
+
end
|
117
|
+
context 'and query has options' do
|
118
|
+
it 'should use the query options for field' do
|
119
|
+
query_options = { weight: 2 }
|
120
|
+
options[:query] = query_options
|
121
|
+
subject.field(field_name, options)
|
122
|
+
expect(subject.context[:query_options][:fields][field_name]).to eq(query_options)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
it_behaves_like 'and options :as is also passed' do
|
127
|
+
let(:options) { { query: true } }
|
128
|
+
let(:custom_options) { subject.context[:query_options][:fields] }
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'when options :facet is passed in' do
|
133
|
+
let(:options) {{ facet: true }}
|
134
|
+
context 'and facet is set to true' do
|
135
|
+
it 'should add facet options for field' do
|
136
|
+
subject.field(field_name, options)
|
137
|
+
expect(subject.context[:facet][field_name]).to eq({})
|
138
|
+
end
|
139
|
+
end
|
140
|
+
context 'and facet has options' do
|
141
|
+
it 'should use the facet options defined' do
|
142
|
+
facet_options = { size: 2 }
|
143
|
+
options[:facet] = facet_options
|
144
|
+
subject.field(field_name, options)
|
145
|
+
expect(subject.context[:facet][field_name]).to eq(facet_options)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
it_behaves_like 'and options :as is also passed' do
|
150
|
+
let(:options) { { facet: true } }
|
151
|
+
let(:custom_options) { subject.context[:facet] }
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'when options :as is passed in' do
|
156
|
+
let(:options) {{ override: false }}
|
157
|
+
context 'and filter_query fields contains an options for field :as' do
|
158
|
+
let(:original_option) {{ hello: 'world', override: true }}
|
159
|
+
let(:real_name) { :text1 }
|
160
|
+
before {
|
161
|
+
options[:as] = real_name
|
162
|
+
((subject.context[:filter_query] ||= {})[:fields] ||= {})[:text1] = original_option
|
163
|
+
}
|
164
|
+
it 'should delete the filter_query fields options for :as field' do
|
165
|
+
expect(subject.context[:filter_query][:fields]).to receive(:delete).with(real_name)
|
166
|
+
subject.field field_name, options
|
167
|
+
end
|
168
|
+
it 'should merge the original options into the new options' do
|
169
|
+
subject.field field_name, options
|
170
|
+
expect(subject.context[:filter_query][:fields][field_name]).to include({hello: 'world' })
|
171
|
+
end
|
172
|
+
it 'should not override the new options' do
|
173
|
+
subject.field field_name, options
|
174
|
+
expect(subject.context[:filter_query][:fields][field_name]).to include(override: false)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
context 'when options :default is passed in' do
|
180
|
+
let(:proc) { Proc.new { } }
|
181
|
+
let(:options) {{ default: proc }}
|
182
|
+
it 'should remove the default lambda or proc from the options' do
|
183
|
+
expect(options).to receive(:delete).with(:default)
|
184
|
+
subject.field field_name, options
|
185
|
+
end
|
186
|
+
it 'should create a literal node using Query::Domain::Literal' do
|
187
|
+
domain = Query::Domain::Literal.new(field_name, {}, self)
|
188
|
+
expect(Query::Domain::Literal).to receive(:new).with(field_name, {}, self).and_return(domain)
|
189
|
+
expect(domain).to receive(:_eval) { |&block| expect(block).to eq proc }
|
190
|
+
subject.field field_name, options
|
191
|
+
end
|
192
|
+
|
193
|
+
context 'when default proc/lambda returns value' do
|
194
|
+
let(:proc) { Proc.new { "name" } }
|
195
|
+
it 'should store the literal node in filter query defaults of context' do
|
196
|
+
node = Query::Domain::Literal.new(field_name, {}, self)._eval(&proc)
|
197
|
+
allow_any_instance_of(Query::Domain::Literal).to receive(:_eval).and_return(node)
|
198
|
+
expect{ subject.field field_name, options }.to change{ subject.context[:filter_query] }.from(nil).to(hash_including(defaults: include(node)))
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
context 'when default proc/lambda returns nothing' do
|
203
|
+
it 'should not create any literal node in filter query defaults of context' do
|
204
|
+
node = Query::Domain::Literal.new(field_name, {}, self)._eval(&proc)
|
205
|
+
allow_any_instance_of(Query::Domain::Literal).to receive(:_eval).and_return(node)
|
206
|
+
expect{ subject.field field_name, options }.to_not change{ subject.send(:filter_query_defaults) }.from([])
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'should create an field accessor' do
|
212
|
+
field_name = :an_indexed_field
|
213
|
+
expect{ subject.field field_name, {} }.to change{ Query::DSL::FieldAccessors.instance_methods }.by([field_name])
|
214
|
+
end
|
215
|
+
|
216
|
+
context 'when options is passed in' do
|
217
|
+
let(:options) {{ hello: "world" }}
|
218
|
+
it 'should store the options in filter query fields' do
|
219
|
+
subject.field field_name, options
|
220
|
+
expect(subject.context[:filter_query][:fields][field_name]).to eq options
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
context 'when no options is passed in' do
|
225
|
+
it 'should create a options in filter query fields' do
|
226
|
+
subject.field field_name
|
227
|
+
expect(subject.context[:filter_query][:fields][field_name]).to eq({})
|
228
|
+
end
|
229
|
+
end
|
20
230
|
end
|
21
231
|
|
22
|
-
describe '#
|
232
|
+
describe '#scope' do
|
233
|
+
let(:scope_name) { :test_scope }
|
234
|
+
context 'when no proc or block is given' do
|
235
|
+
it 'should not add anything to filter query scopes' do
|
236
|
+
expect{ subject.scope(scope_name) }.to_not change{ subject.send(:filter_query_scopes) }
|
237
|
+
end
|
238
|
+
end
|
239
|
+
context 'when proc is given' do
|
240
|
+
let(:proc) { Proc.new {} }
|
241
|
+
it 'should add the proc to the filter query scopes' do
|
242
|
+
expect{ subject.scope(scope_name, proc) }.to change{ subject.send(:filter_query_scopes) }.from({}).to(hash_including( scope_name => proc))
|
243
|
+
end
|
244
|
+
end
|
245
|
+
context 'when block is given' do
|
246
|
+
let(:block) { -> { "block" } }
|
247
|
+
it 'should add the block to the filter query scopes' do
|
248
|
+
expect{ subject.scope(scope_name, &block) }.to change{ subject.send(:filter_query_scopes) }.from({}).to(scope_name => eq(block))
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
context 'when method missing' do
|
254
|
+
let(:undefined_method) { :undefined_method }
|
255
|
+
let(:args) { [1,2,3] }
|
256
|
+
context 'and builder resposnds to the method' do
|
257
|
+
let(:builder) { subject.builder }
|
258
|
+
before { allow(subject).to receive(:builder).and_return(builder) }
|
259
|
+
it 'should check if builder responds to the method' do
|
260
|
+
expect(builder).to receive(:respond_to?).with(undefined_method)
|
261
|
+
subject.undefined_method rescue nil
|
262
|
+
end
|
263
|
+
it 'should call method on builder with parameters passed in' do
|
264
|
+
allow(builder).to receive(:respond_to?).and_return(true)
|
265
|
+
expect(builder).to receive(undefined_method).with(*args)
|
266
|
+
subject.undefined_method(*args)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
context 'and builder not responds to the methods but searchable do' do
|
271
|
+
it 'should check if callee existing and responds to the method' do
|
272
|
+
expect(searchable).to receive(:respond_to?).with(undefined_method)
|
273
|
+
subject.undefined_method rescue nil
|
274
|
+
end
|
275
|
+
it 'should call method on searchable with parameters passed in' do
|
276
|
+
allow(searchable).to receive(:respond_to?).and_return(true)
|
277
|
+
expect(searchable).to receive(undefined_method).with(*args)
|
278
|
+
subject.undefined_method(*args)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
context 'both builder and searchable do not respond to the method' do
|
283
|
+
it 'should raise NoMethodError on subject' do
|
284
|
+
expect{ subject.undefined_method }.to raise_error(NoMethodError)
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
23
288
|
end
|
24
289
|
|
25
290
|
end
|