datagrid 1.8.2 → 2.0.0.pre.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -1
  3. data/{Readme.markdown → README.md} +44 -27
  4. data/app/assets/stylesheets/datagrid.css +145 -0
  5. data/app/views/datagrid/_enum_checkboxes.html.erb +5 -3
  6. data/app/views/datagrid/_form.html.erb +4 -4
  7. data/app/views/datagrid/_head.html.erb +26 -3
  8. data/app/views/datagrid/_range_filter.html.erb +5 -3
  9. data/app/views/datagrid/_row.html.erb +12 -1
  10. data/app/views/datagrid/_table.html.erb +4 -4
  11. data/datagrid.gemspec +6 -6
  12. data/lib/datagrid/active_model.rb +9 -17
  13. data/lib/datagrid/base.rb +39 -0
  14. data/lib/datagrid/column_names_attribute.rb +9 -11
  15. data/lib/datagrid/columns/column.rb +155 -133
  16. data/lib/datagrid/columns.rb +254 -45
  17. data/lib/datagrid/configuration.rb +23 -10
  18. data/lib/datagrid/core.rb +89 -54
  19. data/lib/datagrid/deprecated_object.rb +20 -0
  20. data/lib/datagrid/drivers/abstract_driver.rb +12 -23
  21. data/lib/datagrid/drivers/active_record.rb +24 -26
  22. data/lib/datagrid/drivers/array.rb +22 -14
  23. data/lib/datagrid/drivers/mongo_mapper.rb +15 -14
  24. data/lib/datagrid/drivers/mongoid.rb +15 -17
  25. data/lib/datagrid/drivers/sequel.rb +14 -19
  26. data/lib/datagrid/drivers.rb +2 -1
  27. data/lib/datagrid/engine.rb +11 -3
  28. data/lib/datagrid/filters/base_filter.rb +166 -142
  29. data/lib/datagrid/filters/boolean_filter.rb +19 -5
  30. data/lib/datagrid/filters/date_filter.rb +33 -35
  31. data/lib/datagrid/filters/date_time_filter.rb +24 -16
  32. data/lib/datagrid/filters/default_filter.rb +9 -3
  33. data/lib/datagrid/filters/dynamic_filter.rb +151 -105
  34. data/lib/datagrid/filters/enum_filter.rb +43 -19
  35. data/lib/datagrid/filters/extended_boolean_filter.rb +39 -30
  36. data/lib/datagrid/filters/float_filter.rb +16 -5
  37. data/lib/datagrid/filters/integer_filter.rb +21 -10
  38. data/lib/datagrid/filters/ranged_filter.rb +66 -45
  39. data/lib/datagrid/filters/select_options.rb +58 -49
  40. data/lib/datagrid/filters/string_filter.rb +9 -4
  41. data/lib/datagrid/filters.rb +190 -57
  42. data/lib/datagrid/form_builder.rb +116 -128
  43. data/lib/datagrid/generators/scaffold.rb +185 -0
  44. data/lib/datagrid/generators/views.rb +20 -0
  45. data/lib/datagrid/helper.rb +397 -22
  46. data/lib/datagrid/ordering.rb +26 -29
  47. data/lib/datagrid/rspec.rb +6 -10
  48. data/lib/datagrid/utils.rb +37 -30
  49. data/lib/datagrid/version.rb +3 -1
  50. data/lib/datagrid.rb +18 -28
  51. data/templates/base.rb.erb +6 -4
  52. data/templates/grid.rb.erb +1 -1
  53. metadata +15 -16
  54. data/app/assets/stylesheets/datagrid.sass +0 -134
  55. data/lib/datagrid/filters/composite_filters.rb +0 -49
  56. data/lib/datagrid/renderer.rb +0 -157
  57. data/lib/datagrid/scaffold.rb +0 -129
  58. data/lib/tasks/datagrid_tasks.rake +0 -15
  59. data/templates/controller.rb.erb +0 -6
  60. data/templates/index.html.erb +0 -5
@@ -1,25 +1,33 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "datagrid/filters/ranged_filter"
2
4
 
3
- class Datagrid::Filters::DateTimeFilter < Datagrid::Filters::BaseFilter
5
+ module Datagrid
6
+ module Filters
7
+ class DateTimeFilter < Datagrid::Filters::BaseFilter
8
+ include Datagrid::Filters::RangedFilter
4
9
 
5
- include Datagrid::Filters::RangedFilter
10
+ def default_input_options
11
+ { **super, type: "datetime-local" }
12
+ end
6
13
 
7
- def parse(value)
8
- Datagrid::Utils.parse_datetime(value)
9
- end
14
+ def parse(value)
15
+ Datagrid::Utils.parse_datetime(value)
16
+ end
10
17
 
11
- def format(value)
12
- if formats.any? && value
13
- value.strftime(formats.first)
14
- else
15
- super
16
- end
17
- end
18
+ def format(value)
19
+ if formats.any? && value
20
+ value.strftime(formats.first)
21
+ else
22
+ super
23
+ end
24
+ end
18
25
 
19
- protected
26
+ protected
20
27
 
21
- def formats
22
- Array(Datagrid.configuration.datetime_formats)
28
+ def formats
29
+ Array(Datagrid.configuration.datetime_formats)
30
+ end
31
+ end
23
32
  end
24
33
  end
25
-
@@ -1,5 +1,11 @@
1
- class Datagrid::Filters::DefaultFilter < Datagrid::Filters::BaseFilter
2
- def parse(value)
3
- value
1
+ # frozen_string_literal: true
2
+
3
+ module Datagrid
4
+ module Filters
5
+ class DefaultFilter < Datagrid::Filters::BaseFilter
6
+ def parse(value)
7
+ value
8
+ end
9
+ end
4
10
  end
5
11
  end
@@ -1,125 +1,171 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "datagrid/filters/select_options"
2
4
 
3
- class Datagrid::Filters::DynamicFilter < Datagrid::Filters::BaseFilter
4
-
5
- include Datagrid::Filters::SelectOptions
6
-
7
- EQUAL_OPERATION = '='
8
- LIKE_OPERATION = '=~'
9
- MORE_EQUAL_OPERATION = '>='
10
- LESS_EQUAL_OPERATION = '<='
11
- DEFAULT_OPERATIONS = [
12
- EQUAL_OPERATION,
13
- LIKE_OPERATION,
14
- MORE_EQUAL_OPERATION,
15
- LESS_EQUAL_OPERATION,
16
- ]
17
- AVAILABLE_OPERATIONS = %w(= =~ >= <=)
18
-
19
- def initialize(*)
20
- super
21
- options[:select] ||= default_select
22
- options[:operations] ||= DEFAULT_OPERATIONS
23
- unless options.has_key?(:include_blank)
24
- options[:include_blank] = false
25
- end
26
- end
5
+ module Datagrid
6
+ module Filters
7
+ class DynamicFilter < Datagrid::Filters::BaseFilter
8
+ include Datagrid::Filters::SelectOptions
27
9
 
28
- def parse_values(filter)
29
- field, operation, value = filter
10
+ EQUAL_OPERATION = "="
11
+ LIKE_OPERATION = "=~"
12
+ MORE_EQUAL_OPERATION = ">="
13
+ LESS_EQUAL_OPERATION = "<="
14
+ DEFAULT_OPERATIONS = [
15
+ EQUAL_OPERATION,
16
+ LIKE_OPERATION,
17
+ MORE_EQUAL_OPERATION,
18
+ LESS_EQUAL_OPERATION,
19
+ ].freeze
20
+ AVAILABLE_OPERATIONS = %w[= =~ >= <=].freeze
30
21
 
31
- [field, operation, type_cast(field, value)]
32
- end
22
+ def initialize(grid, name, **options, &block)
23
+ options[:select] ||= default_select
24
+ options[:operations] ||= DEFAULT_OPERATIONS
25
+ options[:include_blank] = false unless options.key?(:include_blank)
26
+ super
27
+ end
33
28
 
34
- def unapplicable_value?(filter)
35
- _, _, value = filter
36
- super(value)
37
- end
29
+ def default_input_options
30
+ { **super, type: nil }
31
+ end
38
32
 
39
- def default_filter_where(scope, filter)
40
- field, operation, value = filter
41
- date_conversion = value.is_a?(Date) && driver.is_timestamp?(scope, field)
33
+ def parse_values(filter)
34
+ filter ? FilterValue.new(grid_class, filter) : nil
35
+ end
42
36
 
43
- return scope if field.blank? || operation.blank?
44
- unless operations.include?(operation)
45
- raise Datagrid::FilteringError, "Unknown operation: #{operation.inspect}. Available operations: #{operations.join(' ')}"
46
- end
47
- case operation
48
- when EQUAL_OPERATION
49
- if date_conversion
50
- value = Datagrid::Utils.format_date_as_timestamp(value)
37
+ def unapplicable_value?(filter)
38
+ super(filter&.value)
51
39
  end
52
- driver.where(scope, field, value)
53
- when LIKE_OPERATION
54
- if column_type(field) == :string
55
- driver.contains(scope, field, value)
56
- else
57
- if date_conversion
58
- value = Datagrid::Utils.format_date_as_timestamp(value)
40
+
41
+ def default_filter_where(scope, filter)
42
+ field = filter.field
43
+ operation = filter.operation
44
+ value = filter.value
45
+ date_conversion = value.is_a?(Date) && driver.timestamp_column?(scope, field)
46
+
47
+ return scope if field.blank? || operation.blank?
48
+
49
+ unless operations.include?(operation)
50
+ raise Datagrid::FilteringError,
51
+ "Unknown operation: #{operation.inspect}. Available operations: #{operations.join(' ')}"
52
+ end
53
+
54
+ case operation
55
+ when EQUAL_OPERATION
56
+ value = Datagrid::Utils.format_date_as_timestamp(value) if date_conversion
57
+ driver.where(scope, field, value)
58
+ when LIKE_OPERATION
59
+ if column_type(field) == :string
60
+ driver.contains(scope, field, value)
61
+ else
62
+ value = Datagrid::Utils.format_date_as_timestamp(value) if date_conversion
63
+ driver.where(scope, field, value)
64
+ end
65
+ when MORE_EQUAL_OPERATION
66
+ value = value.beginning_of_day if date_conversion
67
+ driver.greater_equal(scope, field, value)
68
+ when LESS_EQUAL_OPERATION
69
+ value = value.end_of_day if date_conversion
70
+ driver.less_equal(scope, field, value)
71
+ else
72
+ raise Datagrid::FilteringError,
73
+ "Unknown operation: #{operation.inspect}. Use filter block argument to implement operation"
59
74
  end
60
- driver.where(scope, field, value)
61
- end
62
- when MORE_EQUAL_OPERATION
63
- if date_conversion
64
- value = value.beginning_of_day
65
75
  end
66
- driver.greater_equal(scope, field, value)
67
- when LESS_EQUAL_OPERATION
68
- if date_conversion
69
- value = value.end_of_day
76
+
77
+ def operations
78
+ options[:operations]
70
79
  end
71
- driver.less_equal(scope, field, value)
72
- else
73
- raise Datagrid::FilteringError, "Unknown operation: #{operation.inspect}. Use filter block argument to implement operation"
74
- end
75
- end
76
80
 
77
- def operations
78
- options[:operations]
79
- end
81
+ def operations_select
82
+ operations.map do |operation|
83
+ [I18n.t(operation, scope: "datagrid.filters.dynamic.operations"), operation]
84
+ end
85
+ end
80
86
 
81
- def operations_select
82
- operations.map do |operation|
83
- [I18n.t(operation, scope: "datagrid.filters.dynamic.operations").html_safe, operation]
84
- end
85
- end
87
+ protected
86
88
 
87
- protected
89
+ def default_select
90
+ proc { |grid|
91
+ grid.driver.column_names(grid.scope).map do |name|
92
+ # Mongodb/Rails problem:
93
+ # '_id'.humanize returns ''
94
+ [name.gsub(%r{^_}, "").humanize.strip, name]
95
+ end
96
+ }
97
+ end
88
98
 
89
- def default_select
90
- proc {|grid|
91
- grid.driver.column_names(grid.scope).map do |name|
92
- # Mongodb/Rails problem:
93
- # '_id'.humanize returns ''
94
- [name.gsub(/^_/, '').humanize.strip, name]
99
+ def column_type(field)
100
+ grid_class.driver.normalized_column_type(grid_class.scope, field)
95
101
  end
96
- }
97
- end
98
102
 
99
- def type_cast(field, value)
100
- type = column_type(field)
101
- return nil if value.blank?
102
- case type
103
- when :string
104
- value.to_s
105
- when :integer
106
- value.is_a?(Numeric) || value =~ /^\d/ ? value.to_i : nil
107
- when :float
108
- value.is_a?(Numeric) || value =~ /^\d/ ? value.to_f : nil
109
- when :date
110
- Datagrid::Utils.parse_date(value)
111
- when :timestamp
112
- Datagrid::Utils.parse_date(value)
113
- when :boolean
114
- Datagrid::Utils.booleanize(value)
115
- when nil
116
- value
117
- else
118
- raise NotImplementedError, "unknown column type: #{type.inspect}"
119
- end
120
- end
103
+ class FilterValue
104
+ attr_accessor :field, :operation, :value
105
+
106
+ def initialize(grid_class, object = nil)
107
+ super()
108
+
109
+ case object
110
+ when Hash
111
+ object = object.symbolize_keys
112
+ self.field = object[:field]
113
+ self.operation = object[:operation]
114
+ self.value = object[:value]
115
+ when Array
116
+ self.field = object[0]
117
+ self.operation = object[1]
118
+ self.value = object[2]
119
+ else
120
+ raise ArgumentError, object.inspect
121
+ end
122
+ return unless grid_class
123
+
124
+ type = grid_class.driver.normalized_column_type(
125
+ grid_class.scope, field,
126
+ )
127
+ self.value = type_cast(type, value)
128
+ end
129
+
130
+ def inspect
131
+ { field: field, operation: operation, value: value }
132
+ end
121
133
 
122
- def column_type(field)
123
- grid_class.driver.normalized_column_type(grid_class.scope, field)
134
+ def to_ary
135
+ to_a
136
+ end
137
+
138
+ def to_a
139
+ [field, operation, value]
140
+ end
141
+
142
+ def to_h
143
+ { field: field, operation: operation, value: value }
144
+ end
145
+
146
+ protected
147
+
148
+ def type_cast(type, value)
149
+ return nil if value.blank?
150
+
151
+ case type
152
+ when :string
153
+ value.to_s
154
+ when :integer
155
+ value.is_a?(Numeric) || value =~ %r{^\d} ? value.to_i : nil
156
+ when :float
157
+ value.is_a?(Numeric) || value =~ %r{^\d} ? value.to_f : nil
158
+ when :date, :timestamp
159
+ Datagrid::Utils.parse_date(value)
160
+ when :boolean
161
+ Datagrid::Utils.booleanize(value)
162
+ when nil
163
+ value
164
+ else
165
+ raise NotImplementedError, "unknown column type: #{type.inspect}"
166
+ end
167
+ end
168
+ end
169
+ end
124
170
  end
125
171
  end
@@ -1,28 +1,52 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "datagrid/filters/select_options"
2
4
 
3
- class Datagrid::Filters::EnumFilter < Datagrid::Filters::BaseFilter
5
+ module Datagrid
6
+ module Filters
7
+ class EnumFilter < Datagrid::Filters::BaseFilter
8
+ include Datagrid::Filters::SelectOptions
4
9
 
5
- include Datagrid::Filters::SelectOptions
10
+ # @!visibility private
11
+ def initialize(grid, name, **options, &block)
12
+ options[:multiple] = true if options[:checkboxes]
13
+ super
14
+ raise Datagrid::ConfigurationError, ":select option not specified" unless options[:select]
15
+ end
6
16
 
7
- def initialize(*args)
8
- super(*args)
9
- if checkboxes?
10
- options[:multiple] = true
11
- end
12
- raise Datagrid::ConfigurationError, ":select option not specified" unless options[:select]
13
- end
17
+ def parse(value)
18
+ return nil if strict && !select.include?(value)
14
19
 
15
- def parse(value)
16
- return nil if self.strict && !select.include?(value)
17
- value
18
- end
20
+ value
21
+ end
19
22
 
20
- def strict
21
- options[:strict]
22
- end
23
+ def default_input_options
24
+ {
25
+ **super,
26
+ type: enum_checkboxes? ? "checkbox" : "select",
27
+ multiple: multiple?,
28
+ include_hidden: enum_checkboxes? ? false : nil,
29
+ }
30
+ end
23
31
 
24
- def checkboxes?
25
- options[:checkboxes]
26
- end
32
+ def label_options
33
+ if enum_checkboxes?
34
+ # Each checkbox has its own label
35
+ # The main label has no specific input to focus
36
+ # See app/views/datagrid/_enum_checkboxes.html.erb
37
+ { for: nil, **super }
38
+ else
39
+ super
40
+ end
41
+ end
42
+
43
+ def strict
44
+ options[:strict]
45
+ end
27
46
 
47
+ def enum_checkboxes?
48
+ options[:checkboxes]
49
+ end
50
+ end
51
+ end
28
52
  end
@@ -1,40 +1,49 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # @!visibility private
2
- class Datagrid::Filters::ExtendedBooleanFilter < Datagrid::Filters::EnumFilter
4
+ module Datagrid
5
+ module Filters
6
+ class ExtendedBooleanFilter < Datagrid::Filters::EnumFilter
7
+ YES = "YES"
8
+ NO = "NO"
9
+ TRUTH_VALUES = [true, "true", "y", "yes"].freeze
10
+ FALSE_VALUES = [false, "false", "n", "no"].freeze
3
11
 
4
- YES = "YES"
5
- NO = "NO"
6
- TRUTH_VALUES = [true, 'true', "y", "yes"]
7
- FALSE_VALUES = [false, 'false', "n", "no"]
12
+ def initialize(*args, **options)
13
+ options[:select] = -> { boolean_select }
14
+ super
15
+ end
8
16
 
9
- def initialize(report, attribute, options = {}, &block)
10
- options[:select] = -> { boolean_select }
11
- super(report, attribute, options, &block)
12
- end
17
+ def execute(value, scope, grid_object)
18
+ value = value.blank? ? nil : ::Datagrid::Utils.booleanize(value)
19
+ super
20
+ end
13
21
 
14
- def execute(value, scope, grid_object)
15
- value = value.blank? ? nil : ::Datagrid::Utils.booleanize(value)
16
- super(value, scope, grid_object)
17
- end
22
+ def default_input_options
23
+ { **super, type: "select" }
24
+ end
18
25
 
19
- def parse(value)
20
- value = value.downcase if value.is_a?(String)
21
- case value
22
- when *TRUTH_VALUES
23
- YES
24
- when *FALSE_VALUES
25
- NO
26
- when value.blank?
27
- nil
28
- else
29
- super(value)
30
- end
31
- end
26
+ def parse(value)
27
+ value = value.downcase if value.is_a?(String)
28
+ case value
29
+ when *TRUTH_VALUES
30
+ YES
31
+ when *FALSE_VALUES
32
+ NO
33
+ when value.blank?
34
+ nil
35
+ else
36
+ super
37
+ end
38
+ end
32
39
 
33
- protected
40
+ protected
34
41
 
35
- def boolean_select
36
- [YES, NO].map do |key, value|
37
- [I18n.t("datagrid.filters.xboolean.#{key.downcase}"), key]
42
+ def boolean_select
43
+ [YES, NO].map do |key, _value|
44
+ [I18n.t("datagrid.filters.xboolean.#{key.downcase}"), key]
45
+ end
46
+ end
38
47
  end
39
48
  end
40
49
  end
@@ -1,9 +1,20 @@
1
- class Datagrid::Filters::FloatFilter < Datagrid::Filters::BaseFilter
1
+ # frozen_string_literal: true
2
2
 
3
- include Datagrid::Filters::RangedFilter
3
+ # @!visibility private
4
+ module Datagrid
5
+ module Filters
6
+ class FloatFilter < Datagrid::Filters::BaseFilter
7
+ include Datagrid::Filters::RangedFilter
4
8
 
5
- def parse(value)
6
- return nil if value.blank?
7
- value.to_f
9
+ def default_input_options
10
+ { **super, type: "number", step: "any" }
11
+ end
12
+
13
+ def parse(value)
14
+ return nil if value.blank?
15
+
16
+ value.to_f
17
+ end
18
+ end
8
19
  end
9
20
  end
@@ -1,17 +1,28 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "datagrid/filters/ranged_filter"
2
4
 
3
- class Datagrid::Filters::IntegerFilter < Datagrid::Filters::BaseFilter
5
+ module Datagrid
6
+ module Filters
7
+ class IntegerFilter < Datagrid::Filters::BaseFilter
8
+ include Datagrid::Filters::RangedFilter
9
+
10
+ def default_input_options
11
+ { **super, type: "number", step: "1" }
12
+ end
4
13
 
5
- include Datagrid::Filters::RangedFilter
14
+ def parse(value)
15
+ return nil if value.blank?
16
+ if defined?(ActiveRecord) && value.is_a?(ActiveRecord::Base) &&
17
+ value.respond_to?(:id) && value.id.is_a?(Integer)
18
+ return value.id
19
+ end
20
+ return value if value.is_a?(Range)
6
21
 
7
- def parse(value)
8
- return nil if value.blank?
9
- if defined?(ActiveRecord) && value.is_a?(ActiveRecord::Base) &&
10
- value.respond_to?(:id) && value.id.is_a?(Integer)
11
- return value.id
22
+ return nil if value.to_i.zero? && value.is_a?(String) && value !~ %r{\A\s*-?0}
23
+
24
+ value.to_i
25
+ end
12
26
  end
13
- return value if value.is_a?(Range)
14
- value.to_i
15
27
  end
16
28
  end
17
-
@@ -1,56 +1,77 @@
1
- module Datagrid::Filters::RangedFilter
1
+ # frozen_string_literal: true
2
2
 
3
- def initialize(grid, name, options, &block)
4
- super(grid, name, options, &block)
5
- if range?
6
- options[:multiple] = true
7
- end
8
- end
3
+ module Datagrid
4
+ module Filters
5
+ module RangedFilter
6
+ SERIALIZED_RANGE = %r{\A(.*)\.{2,3}(.*)\z}
9
7
 
10
- def parse_values(value)
11
- result = super(value)
12
- return result if !range? || result.nil?
13
- # Simulate single point range
14
- return [result, result] unless result.is_a?(Array)
15
-
16
- case result.size
17
- when 0
18
- nil
19
- when 1
20
- result.first
21
- when 2
22
- if result.first && result.last && result.first > result.last
23
- # If wrong range is given - reverse it to be always valid
24
- result.reverse
25
- elsif !result.first && !result.last
26
- nil
27
- else
28
- result
8
+ def parse_values(value)
9
+ return super unless range?
10
+
11
+ case value
12
+ when String
13
+ if ["..", "..."].include?(value)
14
+ nil
15
+ elsif (match = value.match(SERIALIZED_RANGE))
16
+ to_range(match.captures[0], match.captures[1], value.include?("..."))
17
+ else
18
+ super
19
+ end
20
+ when Hash
21
+ parse_hash(value)
22
+ when Array
23
+ parse_array(value)
24
+ when Range
25
+ to_range(value.begin, value.end)
26
+ else
27
+ result = super
28
+ to_range(result, result)
29
+ end
29
30
  end
30
- else
31
- raise ArgumentError, "Can not create a date range from array of more than two: #{result.inspect}"
32
- end
33
31
 
34
- end
32
+ def range?
33
+ options[:range]
34
+ end
35
35
 
36
- def range?
37
- options[:range]
38
- end
36
+ def default_filter_where(scope, value)
37
+ if range? && value.is_a?(Range)
38
+ scope = driver.greater_equal(scope, name, value.begin) if value.begin
39
+ scope = driver.less_equal(scope, name, value.end) if value.end
40
+ scope
41
+ else
42
+ super
43
+ end
44
+ end
39
45
 
40
- def default_filter_where(scope, value)
41
- if range? && value.is_a?(Array)
42
- left, right = value
43
- if left
44
- scope = driver.greater_equal(scope, name, left)
46
+ protected
47
+
48
+ def parse_hash(result)
49
+ to_range(result[:from] || result["from"], result[:to] || result["to"])
45
50
  end
46
- if right
47
- scope = driver.less_equal(scope, name, right)
51
+
52
+ def to_range(from, to, exclusive = false)
53
+ from = parse(from)
54
+ to = parse(to)
55
+ return nil unless to || from
56
+
57
+ # If wrong range is given - reverse it to be always valid
58
+ from, to = to, from if from && to && from > to
59
+ exclusive ? from...to : from..to
48
60
  end
49
- scope
50
- else
51
- super(scope, value)
52
- end
53
- end
54
61
 
62
+ def parse_array(result)
63
+ first = result.first
64
+ last = result.last
55
65
 
66
+ case result.size
67
+ when 0
68
+ nil
69
+ when 1, 2
70
+ to_range(first, last)
71
+ else
72
+ raise ArgumentError, "Can not create a range from array of more than two elements"
73
+ end
74
+ end
75
+ end
76
+ end
56
77
  end