muster 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.yardopts +1 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +132 -0
- data/Rakefile +9 -0
- data/lib/muster.rb +3 -0
- data/lib/muster/rack.rb +72 -0
- data/lib/muster/strategies.rb +6 -0
- data/lib/muster/strategies/active_record.rb +118 -0
- data/lib/muster/strategies/filter_expression.rb +142 -0
- data/lib/muster/strategies/hash.rb +93 -0
- data/lib/muster/strategies/pagination.rb +111 -0
- data/lib/muster/strategies/rack.rb +89 -0
- data/lib/muster/strategies/sort_expression.rb +75 -0
- data/lib/muster/version.rb +4 -0
- data/muster.gemspec +24 -0
- data/spec/muster/rack_spec.rb +37 -0
- data/spec/muster/strategies/active_record_spec.rb +137 -0
- data/spec/muster/strategies/filter_expression_spec.rb +126 -0
- data/spec/muster/strategies/hash_spec.rb +90 -0
- data/spec/muster/strategies/pagination_spec.rb +74 -0
- data/spec/muster/strategies/sort_expression_spec.rb +94 -0
- data/spec/spec_helper.rb +8 -0
- metadata +134 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--protected
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Christopher H. Laco
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
# Muster
|
2
|
+
|
3
|
+
Muster is a gem that turns query string options of varying formats into data structures suitable for
|
4
|
+
easier consumption in things like AR and DataMapper scopes and queries, making API development just a little bit easier.
|
5
|
+
|
6
|
+
require 'muster'
|
7
|
+
|
8
|
+
use Muster::Rack, Muster::Strategies::ActiveRecord, :fields => [:select, :order]
|
9
|
+
|
10
|
+
# GET /people?select=id,name&order=name:desc
|
11
|
+
# in your routes/controllers
|
12
|
+
query = env['muster.query']
|
13
|
+
|
14
|
+
@people = Person.select( query[:select] ).order( query[:order] )
|
15
|
+
|
16
|
+
## Strategies
|
17
|
+
|
18
|
+
The following types of strategies are supported. You can combine them in Rack any way you see fit to match the query string options
|
19
|
+
you want to support.
|
20
|
+
|
21
|
+
### Rack
|
22
|
+
|
23
|
+
Returns the query as parsed by Rack::Utils#parse_query.
|
24
|
+
|
25
|
+
?name=value1&name=value2&choice=1&choice=1
|
26
|
+
|
27
|
+
{ 'name' => ['value1', 'value2'], 'choice' => ['1', '1'] }
|
28
|
+
|
29
|
+
### Hash
|
30
|
+
|
31
|
+
Same as Rack but with support for delimited value separation and unique value detection.
|
32
|
+
|
33
|
+
?name=value1,value2&choice=1&choice=1
|
34
|
+
|
35
|
+
{ 'name' => ['value1', 'value2'], 'choice' => '1' }
|
36
|
+
|
37
|
+
### FilterExpression
|
38
|
+
|
39
|
+
Allows name value pairs to be specified in the query string values for use in filtering methods that take Hashes.
|
40
|
+
Include delimited value and unique value support from above.
|
41
|
+
|
42
|
+
?filter=id:1&filter=name:food #=> { 'filter' => {'id' => '1', 'name' => 'food'} }
|
43
|
+
?filter=id:1&filter=id:2 #=> { 'filter' => {'id' => ['1', '2']} }
|
44
|
+
?filter=id:1|2 #=> { 'filter' => {'id' => ['1', '2']} }
|
45
|
+
?filter=id:1,name:food #=> { 'filter' => {'id' => '1', 'name' => 'food'} }
|
46
|
+
|
47
|
+
### SortExpression
|
48
|
+
|
49
|
+
Returns options with support for dirctional indicators for use in sorting.
|
50
|
+
|
51
|
+
?order=name&order=age #=> { 'order' => ['name asc', 'age asc'] }
|
52
|
+
?order=name:asc&age:desc #=> { 'order' => ['name asc', 'age desc'] }
|
53
|
+
|
54
|
+
### Pagination
|
55
|
+
|
56
|
+
Returns options to support pagination with logic for default page size, not-a-number checks and offset calculations.
|
57
|
+
|
58
|
+
?page=2&per_page=5 #=> { 'pagination' => {'page' => 2, 'per_page' => 5}, 'limit' => 5, 'offset' => 5 }
|
59
|
+
?page=a&page_size=-2 #=> { 'pagination' => {'page' => 1, 'per_page' => 30}, 'limit' => 30, 'offset' => nil}
|
60
|
+
|
61
|
+
|
62
|
+
### ActiveRecord
|
63
|
+
|
64
|
+
Combines many of the strategies above to output ActiveRecord Query interface compatible options.
|
65
|
+
|
66
|
+
?select=id,name&where=status:new&order=name:desc&page=3&page_size=10
|
67
|
+
|
68
|
+
{ 'select' => ['id', 'name'], 'where' => {'status' => 'new'}, 'order' => 'name desc', 'limit' => 10, 'offset' => 20, 'pagination' => {:page => 3, :per_page => 10} }
|
69
|
+
|
70
|
+
query = env['muster.query']
|
71
|
+
Person.select( query[:select] ).where( query[:where] ).order( query[:order] ).offset( query[:offset] ).limit( query[:limit] )
|
72
|
+
|
73
|
+
If you are using WillPaginate, you can also pass in :pagination:
|
74
|
+
|
75
|
+
Person.paginate( query[:paginate] )
|
76
|
+
|
77
|
+
## Installation
|
78
|
+
|
79
|
+
Add this line to your application's Gemfile:
|
80
|
+
|
81
|
+
gem 'muster'
|
82
|
+
|
83
|
+
And then execute:
|
84
|
+
|
85
|
+
$ bundle
|
86
|
+
|
87
|
+
Or install it yourself as:
|
88
|
+
|
89
|
+
$ gem install muster
|
90
|
+
|
91
|
+
## Usage
|
92
|
+
|
93
|
+
### In any Rack application:
|
94
|
+
|
95
|
+
require 'muster'
|
96
|
+
|
97
|
+
use Muster::Rack, Muster::Strategies::ActiveRecord, :fields => [:select, :order]
|
98
|
+
|
99
|
+
# GET /people?select=id,name&order=name:desc
|
100
|
+
# in your routes/controllers
|
101
|
+
query = env['muster.query']
|
102
|
+
|
103
|
+
@people = Person.select( query[:select] ).order( query[:order] )
|
104
|
+
|
105
|
+
You can combine multiple strategies, and their results will be merged
|
106
|
+
|
107
|
+
use Muster::Rack, Muster::Strategies::Hash, :field => :select
|
108
|
+
use Muster::Rack, Muster::Strategies::ActiveRecord, :field => :order
|
109
|
+
|
110
|
+
# GET /people?select=id,name&order=name:desc
|
111
|
+
# in your routes/controllers
|
112
|
+
query = env['muster.query']
|
113
|
+
|
114
|
+
@people = Person.select( query[:select] ).order( query[:order] )
|
115
|
+
|
116
|
+
|
117
|
+
### In any code:
|
118
|
+
|
119
|
+
require 'muster'
|
120
|
+
|
121
|
+
strategy = Muster::Strategies::Hash.new
|
122
|
+
query = strategy.parse(request.query_string)
|
123
|
+
people = Person.select( query[:select] ).order( query[:order] )
|
124
|
+
|
125
|
+
## Contributing
|
126
|
+
|
127
|
+
1. Fork it from https://github.com/claco/muster
|
128
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
129
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
130
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
131
|
+
5. Create new Pull Request
|
132
|
+
|
data/Rakefile
ADDED
data/lib/muster.rb
ADDED
data/lib/muster/rack.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
3
|
+
module Muster
|
4
|
+
|
5
|
+
# Rack middleware plugin for Muster query string parsing
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
#
|
9
|
+
# app = Rack::Builder.new do
|
10
|
+
# use Rack::Muster, Muster::Strategies::Hash, :fields => [:name, :choices]
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# # GET /?name=bob&choices=1&choices=2
|
14
|
+
# match '/' do
|
15
|
+
# env['muster.query'] #=> {'name' => 'bob', 'choices' => ['1', '2']}
|
16
|
+
# end
|
17
|
+
class Rack
|
18
|
+
|
19
|
+
# @attribute [r] app
|
20
|
+
# @return [Object] Rack application middleware is running under
|
21
|
+
attr_reader :app
|
22
|
+
|
23
|
+
# @attribute [r] strategy
|
24
|
+
# @return [Muster::Strategies::Rack] Muster Strategy to run
|
25
|
+
attr_reader :strategy
|
26
|
+
|
27
|
+
# @attribute [r] options
|
28
|
+
# @return [Hash] options to pass to strategy
|
29
|
+
attr_reader :options
|
30
|
+
|
31
|
+
# Key in ENV where processed query string are stored
|
32
|
+
QUERY = 'muster.query'.freeze
|
33
|
+
|
34
|
+
# Key in ENV where the query string that was processed is stored
|
35
|
+
QUERY_STRING = 'muster.query_string'.freeze
|
36
|
+
|
37
|
+
# Creates a new Rack::Muster middleware instance
|
38
|
+
#
|
39
|
+
# @param app [String] Rack application
|
40
|
+
# @param strategy [Muster::Strategies::Rack] Muster query string parsing strategy to run
|
41
|
+
# @param options [Hash] options to pass to the specified strategy
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
#
|
45
|
+
# middleware = Muster::Rack.new(app, Muster::Strategies::Hash, :fields => [:name, :choices])
|
46
|
+
#
|
47
|
+
# strategy = Muster::Strategies::Hash.new(:fields => [:name, :choices])
|
48
|
+
# middleware = Muster::Rack.new(app, strategy)
|
49
|
+
def initialize( app, strategy, options={} )
|
50
|
+
@app = app
|
51
|
+
@strategy = strategy
|
52
|
+
@options = options
|
53
|
+
end
|
54
|
+
|
55
|
+
# Handle Rack request
|
56
|
+
#
|
57
|
+
# @param env [Hash] Rack environment
|
58
|
+
#
|
59
|
+
# @return [Array]
|
60
|
+
def call( env )
|
61
|
+
request = ::Rack::Request.new(env)
|
62
|
+
parser = self.strategy.kind_of?(Class) ? self.strategy.new(options) : self.strategy
|
63
|
+
|
64
|
+
env[QUERY] ||= {}
|
65
|
+
env[QUERY].merge! parser.parse(request.query_string)
|
66
|
+
env[QUERY_STRING] = request.query_string
|
67
|
+
|
68
|
+
@app.call(env)
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'active_support/core_ext/array/wrap'
|
2
|
+
require 'active_support/hash_with_indifferent_access'
|
3
|
+
require 'muster/strategies/hash'
|
4
|
+
require 'muster/strategies/filter_expression'
|
5
|
+
require 'muster/strategies/pagination'
|
6
|
+
require 'muster/strategies/sort_expression'
|
7
|
+
|
8
|
+
module Muster
|
9
|
+
module Strategies
|
10
|
+
|
11
|
+
# Query string parsing strategy that outputs ActiveRecord Query compatible options
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
#
|
15
|
+
# strategy = Muster::Strategies::ActiveRecord.new
|
16
|
+
# results = strategy.parse('select=id,name&where=status:new&order=name:desc')
|
17
|
+
#
|
18
|
+
# # { 'select' => ['id', 'name'], :where => {'status' => 'new}, :order => 'name desc' }
|
19
|
+
# #
|
20
|
+
# # Person.select( results[:select] ).where( results[:where] ).order( results[:order] )
|
21
|
+
class ActiveRecord < Muster::Strategies::Rack
|
22
|
+
|
23
|
+
# Processes a query string and returns a hash of its fields/values
|
24
|
+
#
|
25
|
+
# @param query_string [String] the query string to parse
|
26
|
+
#
|
27
|
+
# @return [Hash]
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
#
|
31
|
+
# results = strategy.parse('select=id,name&where=status:new&order=name:desc')
|
32
|
+
#
|
33
|
+
# # { 'select' => ['id', 'name'], :where => {'status' => 'new}, :order => 'name desc' }
|
34
|
+
def parse( query_string )
|
35
|
+
pagination = self.parse_pagination( query_string )
|
36
|
+
|
37
|
+
parameters = ActiveSupport::HashWithIndifferentAccess.new(
|
38
|
+
:select => self.parse_select(query_string),
|
39
|
+
:order => self.parse_order(query_string),
|
40
|
+
:limit => pagination[:limit],
|
41
|
+
:offset => pagination[:offset],
|
42
|
+
:where => self.parse_where(query_string)
|
43
|
+
)
|
44
|
+
|
45
|
+
parameters.regular_writer('pagination', pagination[:pagination].symbolize_keys)
|
46
|
+
|
47
|
+
return parameters
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
# Returns select clauses for AR queries
|
53
|
+
#
|
54
|
+
# @param query_string [String] the original query string to parse select clauses from
|
55
|
+
#
|
56
|
+
# @return [Array]
|
57
|
+
#
|
58
|
+
# @example
|
59
|
+
#
|
60
|
+
# value = self.parse_select('select=id,name') #=> ['id', 'name']
|
61
|
+
def parse_select( query_string )
|
62
|
+
strategy = Muster::Strategies::Hash.new(:field => :select)
|
63
|
+
results = strategy.parse(query_string)
|
64
|
+
|
65
|
+
return Array.wrap( results[:select] )
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns order by clauses for AR queries
|
69
|
+
#
|
70
|
+
# @param query_string [String] the original query string to parse order clauses from
|
71
|
+
#
|
72
|
+
# @return [Array]
|
73
|
+
#
|
74
|
+
# @example
|
75
|
+
#
|
76
|
+
# value = self.parse_order('order=name:desc') #=> ['name asc']
|
77
|
+
def parse_order( query_string )
|
78
|
+
strategy = Muster::Strategies::SortExpression.new(:field => :order)
|
79
|
+
results = strategy.parse(query_string)
|
80
|
+
|
81
|
+
return Array.wrap( results[:order] )
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns pagination information for AR queries
|
85
|
+
#
|
86
|
+
# @param query_string [String] the original query string to parse pagination from
|
87
|
+
#
|
88
|
+
# @return [Hash]
|
89
|
+
#
|
90
|
+
# @example
|
91
|
+
#
|
92
|
+
# value = self.parse_pagination('page=2&page_size=10') #=> { 'pagination' => {:page => 2, :per_page => 10}, 'limit' => 10, 'offset' => 10 }
|
93
|
+
def parse_pagination( query_string )
|
94
|
+
strategy = Muster::Strategies::Pagination.new(:fields => [:pagination, :limit, :offset])
|
95
|
+
results = strategy.parse(query_string)
|
96
|
+
|
97
|
+
return results
|
98
|
+
end
|
99
|
+
|
100
|
+
# Returns where clauses for AR queries
|
101
|
+
#
|
102
|
+
# @param query_string [String] the original query string to parse where statements from
|
103
|
+
#
|
104
|
+
# @return [Hash]
|
105
|
+
#
|
106
|
+
# @example
|
107
|
+
#
|
108
|
+
# value = self.parse_where('where=id:1') #=> {'id' => '1'}
|
109
|
+
def parse_where( query_string )
|
110
|
+
strategy = Muster::Strategies::FilterExpression.new(:field => :where)
|
111
|
+
results = strategy.parse(query_string)
|
112
|
+
|
113
|
+
return results[:where] || {}
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'active_support/core_ext/array/wrap'
|
2
|
+
require 'muster/strategies/hash'
|
3
|
+
|
4
|
+
module Muster
|
5
|
+
module Strategies
|
6
|
+
|
7
|
+
# Query string parsing strategy with additional value handling options for separating filtering expressions
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# strategy = Muster::Strategies::FilterExpression.new
|
12
|
+
# results = strategy.parse('where=id:1&name:Bob') #=> { 'where' => {'id' => '1', 'name' => 'Bob'} }
|
13
|
+
class FilterExpression < Muster::Strategies::Hash
|
14
|
+
|
15
|
+
# @attribute [r] expression_separator
|
16
|
+
# @return [String,RegEx] when specified, each field value will be split into multiple expressions using the specified separator
|
17
|
+
attr_reader :expression_separator
|
18
|
+
|
19
|
+
# @attribute [r] field_separator
|
20
|
+
# @return [String,RegEx] when specified, each expression will be split into multiple field/values using the specified separator
|
21
|
+
attr_reader :field_separator
|
22
|
+
|
23
|
+
# Create a new Hash parsing strategy
|
24
|
+
#
|
25
|
+
# @param [Hash] options the options available for this method
|
26
|
+
# @option options [optional,Array<Symbol>] :fields when specified, only parse the specified fields
|
27
|
+
# You may also use :field if you only intend to pass one field
|
28
|
+
# @option options [optional,String,RegEx] :expression_separator (/,\s*/) when specified, splits the query string value into multiple expressions
|
29
|
+
# You may pass the separator as a string or a regular expression
|
30
|
+
# @option options [optional,String,RegEx] :field_separator (:) when specified, splits the expression value into multiple field/values
|
31
|
+
# You may pass the separator as a string or a regular expression
|
32
|
+
# @option options [optional,String,RegEx] :value_separator (|) when specified, splits the field value into multiple values
|
33
|
+
# You may pass the separator as a string or a regular expression
|
34
|
+
# @option options [optional,Boolean] :unique_values (true) when true, ensures field values do not contain duplicates
|
35
|
+
#
|
36
|
+
# @example
|
37
|
+
#
|
38
|
+
# strategy = Muster::Strategies::FilterExpression.new
|
39
|
+
# strategy = Muster::Strategies::FilterExpression.new(:unique_values => false)
|
40
|
+
def initialize( options={} )
|
41
|
+
super
|
42
|
+
|
43
|
+
@expression_separator = self.options.fetch(:expression_separator, /,\s*/)
|
44
|
+
@field_separator = self.options.fetch(:field_separator, ':')
|
45
|
+
@value_separator = self.options.fetch(:value_separator, '|')
|
46
|
+
end
|
47
|
+
|
48
|
+
# Processes a query string and returns a hash of its fields/values
|
49
|
+
#
|
50
|
+
# @param query_string [String] the query string to parse
|
51
|
+
#
|
52
|
+
# @return [Hash]
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
#
|
56
|
+
# results = strategy.parse('where=id:1&name:Bob') #=> { 'where' => {'id' => '1', 'name' => 'Bob'} }
|
57
|
+
def parse( query_string )
|
58
|
+
parameters = self.fields_to_parse(query_string)
|
59
|
+
|
60
|
+
parameters.each do |key, value|
|
61
|
+
parameters[key] = self.separate_expressions(value)
|
62
|
+
parameters[key] = self.separate_fields(parameters[key])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
protected
|
67
|
+
|
68
|
+
# Separates values into an Array of expressions using :expression_separator
|
69
|
+
#
|
70
|
+
# @param value [String,Array] the original query string field value to separate
|
71
|
+
#
|
72
|
+
# @return [String,Array] String if a single value exists, Array otherwise
|
73
|
+
#
|
74
|
+
# @example
|
75
|
+
#
|
76
|
+
# value = self.separate_values('where=id:1') #=> {'where' => 'id:1'}
|
77
|
+
# value = self.separate_values('where=id:1,id:2') #=> {'where' => ['id:1', 'id:2']}
|
78
|
+
def separate_expressions( value )
|
79
|
+
values = Array.wrap(value)
|
80
|
+
|
81
|
+
values = values.map do |value|
|
82
|
+
value.split(self.expression_separator)
|
83
|
+
end.flatten
|
84
|
+
|
85
|
+
return (values.size > 1) ? values : values.first
|
86
|
+
end
|
87
|
+
|
88
|
+
# Separates expression field values into an Hash of expression filters using :field_separator
|
89
|
+
#
|
90
|
+
# @param value [String,Array] the expressions field value to separate
|
91
|
+
#
|
92
|
+
# @return [Hash]
|
93
|
+
#
|
94
|
+
# @example
|
95
|
+
#
|
96
|
+
# value = self.separate_fields('id:1') #=> {'id' => '1'}
|
97
|
+
# value = self.separate_values('id:1|2') #=> {'id' => '1|2'}
|
98
|
+
def separate_fields( value )
|
99
|
+
values = Array.wrap(value)
|
100
|
+
|
101
|
+
filters = {}
|
102
|
+
|
103
|
+
values.each do |value|
|
104
|
+
name, value = value.split(self.field_separator, 2)
|
105
|
+
|
106
|
+
if self.value_separator.present?
|
107
|
+
value = self.separate_values(value)
|
108
|
+
end
|
109
|
+
|
110
|
+
filters[name] = filters.has_key?(name) ? [filters[name], value].flatten : value
|
111
|
+
|
112
|
+
if self.unique_values == true && filters[name].instance_of?(Array)
|
113
|
+
filters[name].uniq!
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
return filters
|
118
|
+
end
|
119
|
+
|
120
|
+
# Separates expression filter values into an Array of expression filter values using :value_separator
|
121
|
+
#
|
122
|
+
# @param value [String,Array] the expressions filter value to separate
|
123
|
+
#
|
124
|
+
# @return [String,Array] String if a single value exists, Array otherwise
|
125
|
+
#
|
126
|
+
# @example
|
127
|
+
#
|
128
|
+
# value = self.separate_values('1') #=> '1'
|
129
|
+
# value = self.separate_values('1|2') #=> ['1', '2']
|
130
|
+
def separate_values( value )
|
131
|
+
values = Array.wrap(value)
|
132
|
+
|
133
|
+
values = values.map do |value|
|
134
|
+
value.split(self.value_separator)
|
135
|
+
end.flatten
|
136
|
+
|
137
|
+
return (values.size > 1) ? values : value
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|