search_object 1.1.3 → 1.2.0
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 +4 -4
- data/.projections.json +8 -0
- data/CHANGELOG.md +47 -1
- data/README.md +32 -1
- data/example/app/assets/stylesheets/application.css.scss +2 -0
- data/example/app/models/post_search.rb +17 -5
- data/example/app/views/posts/index.html.slim +1 -0
- data/lib/search_object.rb +1 -0
- data/lib/search_object/base.rb +8 -1
- data/lib/search_object/helper.rb +13 -0
- data/lib/search_object/plugin/enum.rb +70 -0
- data/lib/search_object/search.rb +1 -12
- data/lib/search_object/version.rb +1 -1
- data/search_object.gemspec +1 -0
- data/spec/search_object/base_spec.rb +15 -0
- data/spec/search_object/helper_spec.rb +31 -6
- data/spec/search_object/plugin/enum_spec.rb +130 -0
- data/spec/search_object/plugin/kaminari_spec.rb +1 -2
- metadata +20 -4
- data/spec/support/kaminari_setup.rb +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4cce323b42516f0df8bff1b13275f60dcf0439cf
|
4
|
+
data.tar.gz: 35c0d32d6011eae2946e2758ebcf4222b3392f32
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6df95c9bff5882b28585bf3de86623d2015bdb633fabc8eac0b82e330ce11671ef09f581e7bc25a81e1157db828d0334e513a859bed0971dcfe36e1b906bbace
|
7
|
+
data.tar.gz: 9ef427a40467a42bfde8499f6066de5a98481c66d92c7830b021c992386adf0172bca7df56795ab11c442659103d2902fffcf858f00e8e0608463b47460443b7
|
data/.projections.json
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,52 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
## Version 1.
|
3
|
+
## Version 1.2.0 (unreleased)
|
4
|
+
|
5
|
+
* __[feature]__ `enum` plugin added (@rstankov)
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
class ProductSearch
|
9
|
+
include SearchObject.module(:enum)
|
10
|
+
|
11
|
+
scope { Product.all }
|
12
|
+
|
13
|
+
option :order, enum: %w(popular date)
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
# Gets called when order with 'popular' is given
|
18
|
+
def apply_order_with_popular(scope)
|
19
|
+
scope.by_popularity
|
20
|
+
end
|
21
|
+
|
22
|
+
# Gets called when order with 'date' is given
|
23
|
+
def apply_order_with_date(scope)
|
24
|
+
scope.by_date
|
25
|
+
end
|
26
|
+
|
27
|
+
# Gets called when invalid enum is given
|
28
|
+
def handle_invalid_order(scope, invalid_value)
|
29
|
+
scope
|
30
|
+
end
|
31
|
+
end
|
32
|
+
```
|
33
|
+
|
34
|
+
* __[feature]__ Scope is executed in context of SearchObject::Base context (@rstankov)
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
class ProductSearch
|
38
|
+
include SearchObject.module
|
39
|
+
|
40
|
+
scope { @shop.products }
|
41
|
+
|
42
|
+
def initialize(shop)
|
43
|
+
@shop = shop
|
44
|
+
super
|
45
|
+
end
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
## Version 1.1.3
|
4
50
|
|
5
51
|
* __[feature]__ Passing nil as `scope` in constructor, falls back to default scope (@rstankov)
|
6
52
|
|
data/README.md
CHANGED
@@ -104,9 +104,40 @@ include SearchObject.module(:will_paginate)
|
|
104
104
|
include SearchObject.module(:kaminari)
|
105
105
|
```
|
106
106
|
|
107
|
+
### Enum plugin
|
108
|
+
|
109
|
+
Gives you filter with pre-defined options.
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
class ProductSearch
|
113
|
+
include SearchObject.module(:enum)
|
114
|
+
|
115
|
+
scope { Product.all }
|
116
|
+
|
117
|
+
option :order, enum: %w(popular date)
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
# Gets called when order with 'popular' is given
|
122
|
+
def apply_order_with_popular(scope)
|
123
|
+
scope.by_popularity
|
124
|
+
end
|
125
|
+
|
126
|
+
# Gets called when order with 'date' is given
|
127
|
+
def apply_order_with_date(scope)
|
128
|
+
scope.by_date
|
129
|
+
end
|
130
|
+
|
131
|
+
# (optional) Gets called when invalid enum is given
|
132
|
+
def handle_invalid_order(scope, invalid_value)
|
133
|
+
scope
|
134
|
+
end
|
135
|
+
end
|
136
|
+
```
|
137
|
+
|
107
138
|
### Model plugin
|
108
139
|
|
109
|
-
Extends your search object with ```ActiveModel```, so you can use it in
|
140
|
+
Extends your search object with ```ActiveModel```, so you can use it in Rails forms.
|
110
141
|
|
111
142
|
```ruby
|
112
143
|
class ProductSearch
|
@@ -31,7 +31,9 @@ body { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif !important; f
|
|
31
31
|
fieldset { margin-bottom: 20px; padding: 10px; border: 1px solid #e7e7e7; border-radius: 4px; background-color: #f8f8f8; }
|
32
32
|
fieldset input[type="submit"] { @extend .btn; @extend .btn-default; }
|
33
33
|
fieldset input[type="search"],
|
34
|
+
fieldset select,
|
34
35
|
fieldset input[type="date"] { vertical-align: middle; height: 34px; padding: 6px 12px; margin-right: 10px; }
|
36
|
+
fieldset select { width: 100px; }
|
35
37
|
|
36
38
|
table thead label { color: #428bca; }
|
37
39
|
table thead .active { font-weight: bold; color: black; }
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class PostSearch
|
2
|
-
include SearchObject.module(:model, :sorting, :will_paginate)
|
2
|
+
include SearchObject.module(:model, :sorting, :will_paginate, :enum)
|
3
3
|
|
4
4
|
scope { Post.all }
|
5
5
|
|
@@ -13,6 +13,10 @@ class PostSearch
|
|
13
13
|
option :user_id
|
14
14
|
option :category_name
|
15
15
|
|
16
|
+
option :term, with: :apply_term
|
17
|
+
|
18
|
+
option :rating, enum: %i(low high)
|
19
|
+
|
16
20
|
option :title do |scope, value|
|
17
21
|
scope.where 'title LIKE ?', escape_search_term(value)
|
18
22
|
end
|
@@ -21,10 +25,6 @@ class PostSearch
|
|
21
25
|
scope.where published: true if value.present?
|
22
26
|
end
|
23
27
|
|
24
|
-
option :term do |scope, value|
|
25
|
-
scope.where 'title LIKE :term OR body LIKE :term', term: escape_search_term(value)
|
26
|
-
end
|
27
|
-
|
28
28
|
option :created_after do |scope, value|
|
29
29
|
date = parse_date value
|
30
30
|
scope.where('DATE(created_at) >= ?', date) if date.present?
|
@@ -37,6 +37,18 @@ class PostSearch
|
|
37
37
|
|
38
38
|
private
|
39
39
|
|
40
|
+
def apply_term(scope, value)
|
41
|
+
scope.where 'title LIKE :term OR body LIKE :term', term: escape_search_term(value)
|
42
|
+
end
|
43
|
+
|
44
|
+
def apply_rating_with_low(scope)
|
45
|
+
scope.where 'views_count < 100'
|
46
|
+
end
|
47
|
+
|
48
|
+
def apply_rating_with_high(scope)
|
49
|
+
scope.where 'views_count > 500'
|
50
|
+
end
|
51
|
+
|
40
52
|
def parse_date(value)
|
41
53
|
Date.parse(value).strftime('%Y-%m-%d')
|
42
54
|
rescue
|
@@ -7,6 +7,7 @@
|
|
7
7
|
= form.search_field :term, placeholder: 'Search term'
|
8
8
|
= date_field_tag 'f[created_after]', @search.created_after
|
9
9
|
= date_field_tag 'f[created_before]', @search.created_before
|
10
|
+
= select_tag 'f[rating]', options_for_select([['All', ''], ['Popular', 'high'], ['Unpopular', 'low']], @search.rating)
|
10
11
|
= form.submit 'Search'
|
11
12
|
|
12
13
|
div.pull-right
|
data/lib/search_object.rb
CHANGED
data/lib/search_object/base.rb
CHANGED
@@ -12,7 +12,14 @@ module SearchObject
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def initialize(options = {})
|
15
|
-
|
15
|
+
config = self.class.config
|
16
|
+
scope = options[:scope] || (config[:scope] && instance_eval(&config[:scope]))
|
17
|
+
actions = config[:actions] || {}
|
18
|
+
params = Helper.normalize_params(config[:defaults], options[:filters], actions.keys)
|
19
|
+
|
20
|
+
raise MissingScopeError unless scope
|
21
|
+
|
22
|
+
@search = Search.new(scope, params, actions)
|
16
23
|
end
|
17
24
|
|
18
25
|
def results
|
data/lib/search_object/helper.rb
CHANGED
@@ -21,6 +21,15 @@ module SearchObject
|
|
21
21
|
text.to_s.gsub(/(?:^|_)(.)/) { Regexp.last_match[1].upcase }
|
22
22
|
end
|
23
23
|
|
24
|
+
def underscore(text)
|
25
|
+
text.to_s
|
26
|
+
.tr('::', '_')
|
27
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/) { "#{Regexp.last_match[1]}_#{Regexp.last_match[2]}" }
|
28
|
+
.gsub(/([a-z\d])([A-Z])/) { "#{Regexp.last_match[1]}_#{Regexp.last_match[2]}" }
|
29
|
+
.tr('-', '_')
|
30
|
+
.downcase
|
31
|
+
end
|
32
|
+
|
24
33
|
def ensure_included(item, collection)
|
25
34
|
if collection.include? item
|
26
35
|
item
|
@@ -45,6 +54,10 @@ module SearchObject
|
|
45
54
|
end
|
46
55
|
end
|
47
56
|
|
57
|
+
def normalize_params(defaults, filters, keys)
|
58
|
+
(defaults || {}).merge(slice_keys(stringify_keys(filters || {}), keys || []))
|
59
|
+
end
|
60
|
+
|
48
61
|
def deep_copy(object) # rubocop:disable Metrics/MethodLength
|
49
62
|
case object
|
50
63
|
when Array
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module SearchObject
|
2
|
+
module Plugin
|
3
|
+
module Enum
|
4
|
+
def self.included(base)
|
5
|
+
base.extend ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def option(name, options = nil, &block)
|
10
|
+
return super unless options.is_a?(Hash) && options[:enum]
|
11
|
+
|
12
|
+
raise BlockIgnoredError if block
|
13
|
+
raise WithIgnoredError if options[:with]
|
14
|
+
|
15
|
+
handler = Handler.build(name, options[:enum])
|
16
|
+
|
17
|
+
super(name, options, &handler)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module Handler
|
22
|
+
module_function
|
23
|
+
|
24
|
+
def build(name, enums)
|
25
|
+
enums = enums.map(&:to_s)
|
26
|
+
handler = self
|
27
|
+
->(scope, value) { handler.apply_filter(object: self, option: name, enums: enums, scope: scope, value: value) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def apply_filter(object:, option:, enums:, scope:, value:)
|
31
|
+
return if value.nil? || value == ''
|
32
|
+
|
33
|
+
unless enums.include? value
|
34
|
+
return handle_invalid_value(object: object, option: option, enums: enums, scope: scope, value: value)
|
35
|
+
end
|
36
|
+
|
37
|
+
object.send("apply_#{option}_with_#{Helper.underscore(value)}", scope)
|
38
|
+
end
|
39
|
+
|
40
|
+
def handle_invalid_value(object:, option:, enums:, scope:, value:)
|
41
|
+
specific = "handle_invalid_#{option}"
|
42
|
+
return object.send(specific, scope, value) if object.respond_to? specific, true
|
43
|
+
|
44
|
+
catch_all = 'handle_invalid_enum'
|
45
|
+
return object.send(catch_all, option, scope, value) if object.respond_to? catch_all, true
|
46
|
+
|
47
|
+
raise InvalidEnumValueError.new(option, enums, value)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class InvalidEnumValueError < ArgumentError
|
52
|
+
def initialize(option, enums, value)
|
53
|
+
super "Wrong value '#{value}' used for enum #{option} (expected one of #{enums.join(', ')})"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class BlockIgnoredError < ArgumentError
|
58
|
+
def initialize(message = "Enum options don't accept blocks")
|
59
|
+
super message
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class WithIgnoredError < ArgumentError
|
64
|
+
def initialize(message = "Enum options don't accept :with")
|
65
|
+
super message
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/search_object/search.rb
CHANGED
@@ -1,19 +1,8 @@
|
|
1
1
|
module SearchObject
|
2
|
+
# :api: private
|
2
3
|
class Search
|
3
4
|
attr_reader :params
|
4
5
|
|
5
|
-
class << self
|
6
|
-
def build_for(config, options)
|
7
|
-
scope = options[:scope] || (config[:scope] && config[:scope].call)
|
8
|
-
filters = Helper.stringify_keys(options.fetch(:filters, {}))
|
9
|
-
params = config[:defaults].merge Helper.slice_keys(filters, config[:actions].keys)
|
10
|
-
|
11
|
-
raise MissingScopeError unless scope
|
12
|
-
|
13
|
-
new scope, params, config[:actions]
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
6
|
def initialize(scope, params, actions)
|
18
7
|
@scope = scope
|
19
8
|
@actions = actions
|
data/search_object.gemspec
CHANGED
@@ -28,6 +28,7 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.add_development_dependency 'coveralls'
|
29
29
|
spec.add_development_dependency 'will_paginate'
|
30
30
|
spec.add_development_dependency 'kaminari'
|
31
|
+
spec.add_development_dependency 'kaminari-activerecord'
|
31
32
|
spec.add_development_dependency 'rubocop', '0.46.0'
|
32
33
|
spec.add_development_dependency 'rubocop-rspec', '1.8.0'
|
33
34
|
end
|
@@ -101,6 +101,21 @@ module SearchObject
|
|
101
101
|
expect(search_class.new(scope: 'other scope').results).to eq 'other scope'
|
102
102
|
end
|
103
103
|
|
104
|
+
it 'scope block is exectued in context of search object' do
|
105
|
+
search_class = define_search_class do
|
106
|
+
scope { inner_scope }
|
107
|
+
|
108
|
+
attr_reader :inner_scope
|
109
|
+
|
110
|
+
def initialize
|
111
|
+
@inner_scope = 'scope'
|
112
|
+
super
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
expect(search_class.new.results).to eq 'scope'
|
117
|
+
end
|
118
|
+
|
104
119
|
it 'passing nil as scope in constructor, falls back to default scope' do
|
105
120
|
search_class = define_search_class do
|
106
121
|
scope { 'scope' }
|
@@ -5,32 +5,57 @@ module SearchObject
|
|
5
5
|
describe Helper do
|
6
6
|
describe '.stringify_keys' do
|
7
7
|
it 'converts hash keys to strings' do
|
8
|
-
hash =
|
8
|
+
hash = described_class.stringify_keys a: 1, b: nil, c: false
|
9
9
|
expect(hash).to eq 'a' => 1, 'b' => nil, 'c' => false
|
10
10
|
end
|
11
11
|
|
12
12
|
it 'converts ActionController::Parameters to hash' do
|
13
13
|
params = ::ActionController::Parameters.new a: 1, b: nil, c: false
|
14
|
-
hash =
|
14
|
+
hash = described_class.stringify_keys params
|
15
15
|
expect(hash).to eq 'a' => 1, 'b' => nil, 'c' => false
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
19
|
describe '.slice_keys' do
|
20
20
|
it 'selects only given keys' do
|
21
|
-
hash =
|
21
|
+
hash = described_class.slice_keys({ a: 1, b: 2, c: 3 }, [:a, :b])
|
22
22
|
expect(hash).to eq a: 1, b: 2
|
23
23
|
end
|
24
24
|
|
25
25
|
it 'ignores not existing keys' do
|
26
|
-
hash =
|
26
|
+
hash = described_class.slice_keys({}, [:a, :b])
|
27
27
|
expect(hash).to eq({})
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
31
|
describe 'camelize' do
|
32
32
|
it "transforms :paging to 'Paging'" do
|
33
|
-
expect(
|
33
|
+
expect(described_class.camelize(:paging)).to eq 'Paging'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'underscore' do
|
38
|
+
it "transforms 'veryPopular' to 'very_popular'" do
|
39
|
+
expect(described_class.underscore(:veryPopular)).to eq 'very_popular'
|
40
|
+
expect(described_class.underscore('VERY_POPULAR')).to eq 'very_popular'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '.normalize_filters' do
|
45
|
+
it 'combines defaults and filters' do
|
46
|
+
expect(described_class.normalize_params({ 'a' => 1, 'b' => 2 }, { a: 2 }, %w(a b))).to eq 'a' => 2, 'b' => 2
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'excludes non specified keys' do
|
50
|
+
expect(described_class.normalize_params({ 'a' => 1 }, { b: 2 }, %w(a))).to eq 'a' => 1
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'handles missing defaults' do
|
54
|
+
expect(described_class.normalize_params(nil, { a: 1 }, %w(a))).to eq 'a' => 1
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'handles missing filters' do
|
58
|
+
expect(described_class.normalize_params(nil, nil, ['a'])).to eq({})
|
34
59
|
end
|
35
60
|
end
|
36
61
|
|
@@ -44,7 +69,7 @@ module SearchObject
|
|
44
69
|
null: nil
|
45
70
|
}
|
46
71
|
|
47
|
-
deep_copy =
|
72
|
+
deep_copy = described_class.deep_copy(original)
|
48
73
|
|
49
74
|
original[:array][0] = 42
|
50
75
|
original[:hash][:key] = 'other value'
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
module SearchObject
|
5
|
+
module Plugin
|
6
|
+
describe Enum do
|
7
|
+
class TestSearch
|
8
|
+
include SearchObject.module(:enum)
|
9
|
+
|
10
|
+
scope { [1, 2, 3, 4, 5] }
|
11
|
+
|
12
|
+
option :filter, enum: %w(odd even)
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def apply_filter_with_odd(scope)
|
17
|
+
scope.select(&:odd?)
|
18
|
+
end
|
19
|
+
|
20
|
+
def apply_filter_with_even(scope)
|
21
|
+
scope.select(&:even?)
|
22
|
+
end
|
23
|
+
|
24
|
+
def handle_invalid_filter(_scope, value)
|
25
|
+
"invalid filter - #{value}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'can filter by enum values' do
|
30
|
+
expect(TestSearch.results(filters: { filter: 'odd' })).to eq [1, 3, 5]
|
31
|
+
expect(TestSearch.results(filters: { filter: 'even' })).to eq [2, 4]
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'ignores blank values' do
|
35
|
+
expect(TestSearch.results(filters: { filter: nil })).to eq [1, 2, 3, 4, 5]
|
36
|
+
expect(TestSearch.results(filters: { filter: '' })).to eq [1, 2, 3, 4, 5]
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'handles wrong enum values' do
|
40
|
+
expect(TestSearch.results(filters: { filter: 'foo' })).to eq 'invalid filter - foo'
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'raises when block is passed with enum option' do
|
44
|
+
expect do
|
45
|
+
Class.new do
|
46
|
+
include SearchObject.module(:enum)
|
47
|
+
|
48
|
+
option(:filter, enum: %w(a b)) { |_scope, _value| nil }
|
49
|
+
end
|
50
|
+
end.to raise_error Enum::BlockIgnoredError
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'raises when :with is passed with enum option' do
|
54
|
+
expect do
|
55
|
+
Class.new do
|
56
|
+
include SearchObject.module(:enum)
|
57
|
+
|
58
|
+
option :filter, enum: %w(a b), with: :method_name
|
59
|
+
end
|
60
|
+
end.to raise_error Enum::WithIgnoredError
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe Enum::Handler do
|
65
|
+
describe 'apply_filter' do
|
66
|
+
def new_object(&block)
|
67
|
+
klass = Class.new(&block)
|
68
|
+
klass.new
|
69
|
+
end
|
70
|
+
|
71
|
+
def call(object: nil, option: nil, enums: nil, scope: nil, value:)
|
72
|
+
described_class.apply_filter(
|
73
|
+
object: object || new_object,
|
74
|
+
option: option || 'option',
|
75
|
+
enums: enums || [value],
|
76
|
+
scope: scope || [],
|
77
|
+
value: value
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'filters by methods based on the enum value' do
|
82
|
+
object = new_object do
|
83
|
+
private
|
84
|
+
|
85
|
+
def apply_select_with_name(scope)
|
86
|
+
scope.select { |value| value == 'name' }
|
87
|
+
end
|
88
|
+
|
89
|
+
def apply_select_with_age(scope)
|
90
|
+
scope.select { |value| value == 'age' }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
scope = %w(name age location)
|
95
|
+
|
96
|
+
expect(call(object: object, option: 'select', scope: scope, value: 'name')).to eq %w(name)
|
97
|
+
expect(call(object: object, option: 'select', scope: scope, value: 'age')).to eq %w(age)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'raises NoMethodError when object can not handle enum method' do
|
101
|
+
expect { call(enums: ['a'], value: 'a') }.to raise_error NoMethodError
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'raises error when value is not an enum' do
|
105
|
+
expect { call(enums: [], value: 'invalid') }.to raise_error Enum::InvalidEnumValueError
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'can delegate missing enum value to object' do
|
109
|
+
object = new_object do
|
110
|
+
def handle_invalid_option(_scope, value)
|
111
|
+
"handles #{value} value"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
expect(call(object: object, enums: [], value: 'invalid')).to eq 'handles invalid value'
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'can delegate missing enum value to object (cath all)' do
|
119
|
+
object = new_object do
|
120
|
+
def handle_invalid_enum(option, _scope, value)
|
121
|
+
"handles #{value} value for #{option}"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
expect(call(object: object, enums: [], value: 'invalid')).to eq 'handles invalid value for option'
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: search_object
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Radoslav Stankov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-04-
|
11
|
+
date: 2017-04-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -150,6 +150,20 @@ dependencies:
|
|
150
150
|
- - ">="
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: kaminari-activerecord
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
153
167
|
- !ruby/object:Gem::Dependency
|
154
168
|
name: rubocop
|
155
169
|
requirement: !ruby/object:Gem::Requirement
|
@@ -186,6 +200,7 @@ extensions: []
|
|
186
200
|
extra_rdoc_files: []
|
187
201
|
files:
|
188
202
|
- ".gitignore"
|
203
|
+
- ".projections.json"
|
189
204
|
- ".rspec"
|
190
205
|
- ".rubocop.yml"
|
191
206
|
- ".travis.yml"
|
@@ -238,6 +253,7 @@ files:
|
|
238
253
|
- lib/search_object/base.rb
|
239
254
|
- lib/search_object/errors.rb
|
240
255
|
- lib/search_object/helper.rb
|
256
|
+
- lib/search_object/plugin/enum.rb
|
241
257
|
- lib/search_object/plugin/kaminari.rb
|
242
258
|
- lib/search_object/plugin/model.rb
|
243
259
|
- lib/search_object/plugin/paging.rb
|
@@ -248,6 +264,7 @@ files:
|
|
248
264
|
- search_object.gemspec
|
249
265
|
- spec/search_object/base_spec.rb
|
250
266
|
- spec/search_object/helper_spec.rb
|
267
|
+
- spec/search_object/plugin/enum_spec.rb
|
251
268
|
- spec/search_object/plugin/kaminari_spec.rb
|
252
269
|
- spec/search_object/plugin/model_spec.rb
|
253
270
|
- spec/search_object/plugin/paging_spec.rb
|
@@ -256,7 +273,6 @@ files:
|
|
256
273
|
- spec/search_object/search_spec.rb
|
257
274
|
- spec/spec_helper.rb
|
258
275
|
- spec/spec_helper_active_record.rb
|
259
|
-
- spec/support/kaminari_setup.rb
|
260
276
|
- spec/support/paging_shared_example.rb
|
261
277
|
homepage: https://github.com/RStankov/SearchObject
|
262
278
|
licenses:
|
@@ -285,6 +301,7 @@ summary: Provides DSL for creating search objects
|
|
285
301
|
test_files:
|
286
302
|
- spec/search_object/base_spec.rb
|
287
303
|
- spec/search_object/helper_spec.rb
|
304
|
+
- spec/search_object/plugin/enum_spec.rb
|
288
305
|
- spec/search_object/plugin/kaminari_spec.rb
|
289
306
|
- spec/search_object/plugin/model_spec.rb
|
290
307
|
- spec/search_object/plugin/paging_spec.rb
|
@@ -293,5 +310,4 @@ test_files:
|
|
293
310
|
- spec/search_object/search_spec.rb
|
294
311
|
- spec/spec_helper.rb
|
295
312
|
- spec/spec_helper_active_record.rb
|
296
|
-
- spec/support/kaminari_setup.rb
|
297
313
|
- spec/support/paging_shared_example.rb
|