comparability 1.0.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 +7 -0
- data/.gitignore +17 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +22 -0
- data/README.md +126 -0
- data/Rakefile +1 -0
- data/comparability.gemspec +22 -0
- data/lib/comparability.rb +7 -0
- data/lib/comparability/comparable_by.rb +20 -0
- data/lib/comparability/comparator.rb +26 -0
- data/lib/comparability/comparators/attribute_value_comparator.rb +38 -0
- data/lib/comparability/comparators/comparator_chain.rb +38 -0
- data/lib/comparability/comparators/factory_methods.rb +103 -0
- data/lib/comparability/comparators/nil_comparator.rb +45 -0
- data/lib/comparability/comparators/proc_comparator.rb +14 -0
- data/lib/comparability/comparators/reverse_wrapper_comparator.rb +25 -0
- data/lib/comparability/comparators/value_comparator.rb +40 -0
- data/lib/comparability/comparators/value_extractor_comparator.rb +24 -0
- data/lib/comparability/comparators/wrapper_comparator.rb +26 -0
- data/lib/comparability/version.rb +3 -0
- metadata +91 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d7df560ce69d77e22e8c096500a37c2ed83c271c
|
4
|
+
data.tar.gz: 959f6c8776ac7c4922246edd4e5d20e68149c4c8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 66d97494c122f12583f01d78c949a063b28a00d922e4a8a5113edc354e84fe0efbfc248eaf55e956dca16f4319e7c3a1fc6e09b9e54130cbfbc1d8e589ea2bd7
|
7
|
+
data.tar.gz: b3805cdb0f7d3c6a949187b581508fdbbd5965466d63c138ef7d18f8b69660fe0cf17353c1ce21ef378c53efd9ebcdda5ba38e69db7f4edd411951b74a409986
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Ippei Ukai
|
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,126 @@
|
|
1
|
+
# Comparability
|
2
|
+
|
3
|
+
Provides Comparator and declarative definition of comparison operator.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'comparability'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install comparability
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
### ComparableBy (Declarative definition of comparison operator)
|
22
|
+
|
23
|
+
You can declaratively define your class's comparison with ``comparable_by`` method.
|
24
|
+
To use, you need to extend your class with ``ComparableBy`` module.
|
25
|
+
|
26
|
+
require 'comparability'
|
27
|
+
|
28
|
+
class MyClass < Struct.new(:a, :b, :c, :d)
|
29
|
+
extend ComparableBy
|
30
|
+
|
31
|
+
attr_reader :a, :b, :c, :d, :e
|
32
|
+
|
33
|
+
comparable_by :a, # order of a
|
34
|
+
[:b, reverse: true], # reverse order of b
|
35
|
+
[:c, nil: :first], # order of c, ordered first if c is nil
|
36
|
+
[:d, reverse: true, nil: :last] # reverse order of d, ordered last if d is nil
|
37
|
+
->(_){ _.e.upcase }, # order of e, case-insensitive
|
38
|
+
end
|
39
|
+
|
40
|
+
Call of ``comparable_by`` defines ``<=>`` instance method, and includes ``Comparable`` module.
|
41
|
+
Each parameter to ``comparable_by`` should be either an instance of ``Comparator`` or arguments to ``Comparator.create``
|
42
|
+
in order of precedence.
|
43
|
+
|
44
|
+
### Comparator
|
45
|
+
|
46
|
+
Some pre-defined comparisons are accessible with special methods.
|
47
|
+
Other variations are created with ``Comparator.create``.
|
48
|
+
|
49
|
+
#### natural order
|
50
|
+
|
51
|
+
The most simple ``Comparator`` which just evokes the comparison (spaceship) operator.
|
52
|
+
|
53
|
+
Comparator.natural_order # essentially compare(a,b) is defined as a <=> b
|
54
|
+
Comparator.natural_order(reverse: true) # b <=> a instead
|
55
|
+
|
56
|
+
#### nil priority
|
57
|
+
|
58
|
+
This special ``Comparator`` orders only by whether object is nil or not.
|
59
|
+
|
60
|
+
Comparator.prioritize_nil(:first) # nil is smaller
|
61
|
+
Comparator.prioritize_nil(:last) # nil is bigger
|
62
|
+
|
63
|
+
#### by attribute value
|
64
|
+
|
65
|
+
If you specify a symbol to ``Comparator.create``,
|
66
|
+
the comparator will compare objects by the results of the specified method.
|
67
|
+
|
68
|
+
Comparator.create(:size) # compares by size (prioritise smaller)
|
69
|
+
Comparator.create(:size, reverse: true) # compares by size (prioritise bigger)
|
70
|
+
|
71
|
+
You can use ``:nil`` option to specify the priority of nil value.
|
72
|
+
|
73
|
+
Comparator.create(:priority, nil: :last) # compares by priority (prioritise smaller, last if nil)
|
74
|
+
Comparator.create(:priority, reverse: true, nil: :last) # compares by priority (prioritise bigger, last if nil)
|
75
|
+
|
76
|
+
The attribute method can be public or protected, but not private.
|
77
|
+
|
78
|
+
#### by value extractor
|
79
|
+
|
80
|
+
If you specify a proc with arity 1 to ``Comparator.create``,
|
81
|
+
the comparator will compare objects by the results of the specified proc yielding each object.
|
82
|
+
|
83
|
+
You can also pass the comparison as block.
|
84
|
+
|
85
|
+
Comparator.create { |str| str.length } # compares by length (prioritise shorter)
|
86
|
+
Comparator.create { |str| -str.length } # compares by length (prioritise longer)
|
87
|
+
|
88
|
+
#### with proc
|
89
|
+
|
90
|
+
If you specify a proc with arity 2 to ``Comparator.create``,
|
91
|
+
it creates a comparator defined by the specified proc.
|
92
|
+
|
93
|
+
You can also pass the comparison as block.
|
94
|
+
|
95
|
+
Comparator.create do |obj1, obj2|
|
96
|
+
# ... your comparison here ...
|
97
|
+
end
|
98
|
+
|
99
|
+
#### chaining
|
100
|
+
|
101
|
+
You can chain comparators with ``Comparator.chain`` or its alias ``Comparator.[]``.
|
102
|
+
|
103
|
+
Comparator[comparator1, comparator2] # compares with comparator1, then tie-breaks with comparator2
|
104
|
+
|
105
|
+
#### reversing
|
106
|
+
|
107
|
+
You can reverse existing comparators with ``Comparator.reverse``.
|
108
|
+
|
109
|
+
Comparator.reverse(comparator) # reverses the order
|
110
|
+
|
111
|
+
#### ``Enumerable#sort`` usage
|
112
|
+
|
113
|
+
``Comparator#to_proc`` returns a ``Proc`` compatible with ``Enumerable#sort``.
|
114
|
+
You can use the ampersand shorthand to convert a comparator and pass as block.
|
115
|
+
|
116
|
+
comparator = Comparator[Comparator.prioritize_nil(:last),
|
117
|
+
Comparator.natural_order(reverse: true)]
|
118
|
+
[nil,1,2,3,4].sort(&comparator) # => [4, 3, 2, 1, nil]
|
119
|
+
|
120
|
+
## Contributing
|
121
|
+
|
122
|
+
1. Fork it ( http://github.com/ippeiukai/comparability/fork )
|
123
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
124
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
125
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
126
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'comparability/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'comparability'
|
8
|
+
spec.version = Comparability::VERSION
|
9
|
+
spec.authors = ['Ippei Ukai']
|
10
|
+
spec.email = ['ippei@users.sourceforge.net']
|
11
|
+
spec.summary = 'Provides Comparator and declarative definition of comparison operator.'
|
12
|
+
spec.homepage = 'http://github.com/ippeiukai/comparability'
|
13
|
+
spec.license = 'MIT'
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x00")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
|
20
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
21
|
+
spec.add_development_dependency 'rake'
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Comparability
|
4
|
+
module ComparableBy
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
# @!visibility public
|
9
|
+
# Declares the comparison for this class.
|
10
|
+
# This defines <=> instance method and includes Comparable module.
|
11
|
+
def comparable_by(*args)
|
12
|
+
raise ArgumentError if args.empty?
|
13
|
+
comparator = Comparator.chain(*args)
|
14
|
+
const_set(:COMPARATOR, comparator)
|
15
|
+
define_method(:<=>) { |other| self.class::COMPARATOR.compare(self, other) }
|
16
|
+
include Comparable
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Comparability
|
4
|
+
class Comparator
|
5
|
+
# @!parse extend Comparability::Comparators::FactoryMethods
|
6
|
+
|
7
|
+
def compare(me, other)
|
8
|
+
me <=> other
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_proc
|
12
|
+
@_to_proc ||= method(:compare).to_proc
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# require files in ./comparators
|
19
|
+
File.dirname(File.expand_path(__FILE__)).tap do |this_dirname|
|
20
|
+
Dir[File.join(this_dirname, 'comparators', '**', '*.rb')].each do |file|
|
21
|
+
name = file.gsub(%r|^#{Regexp.escape(this_dirname)}/(.*)#{Regexp.escape('.rb')}|, '\1')
|
22
|
+
require_relative name
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
Comparability::Comparator.extend(Comparability::Comparators::FactoryMethods)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require_relative 'value_comparator'
|
4
|
+
|
5
|
+
module Comparability
|
6
|
+
module Comparators
|
7
|
+
class AttributeValueComparator < ValueComparator
|
8
|
+
|
9
|
+
def initialize(attribute)
|
10
|
+
attribute = attribute.to_s.freeze unless attribute.is_a?(Symbol)
|
11
|
+
@attribute = attribute
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :attribute
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def extract_value(me)
|
19
|
+
me.send(attribute)
|
20
|
+
end
|
21
|
+
|
22
|
+
def extract_other_value(me, _other_)
|
23
|
+
if instance_evaluable_attribute?
|
24
|
+
# me can access the protected attribute of the other
|
25
|
+
me.instance_eval("_other_.#{attribute}()")
|
26
|
+
else
|
27
|
+
_other_.public_send(attribute)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
INSTANCE_EVALUABLE_METHOD_NAME = /\A([_a-zA-Z][_a-zA-Z0-9]*[!?]?)|([!~+-]@)\Z/
|
32
|
+
def instance_evaluable_attribute?
|
33
|
+
INSTANCE_EVALUABLE_METHOD_NAME =~ attribute
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
module Comparability
|
6
|
+
module Comparators
|
7
|
+
class ComparatorChain < Comparator
|
8
|
+
extend Forwardable
|
9
|
+
include Enumerable
|
10
|
+
|
11
|
+
def initialize(comparators)
|
12
|
+
raise ArgumentError unless comparators.size > 0
|
13
|
+
raise ArgumentError unless comparators.all? { |c| c.is_a?(Comparator) }
|
14
|
+
@comparators = comparators.freeze
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :comparators
|
18
|
+
delegate :each => :comparators
|
19
|
+
|
20
|
+
def compare(me, other)
|
21
|
+
inject(0) do |zero, comparator|
|
22
|
+
result = comparator.compare(me, other)
|
23
|
+
if result.nil?
|
24
|
+
# the comparator failed
|
25
|
+
return nil
|
26
|
+
elsif result.nonzero?
|
27
|
+
# we have the conclusion
|
28
|
+
return result
|
29
|
+
else
|
30
|
+
# a tie
|
31
|
+
next 0
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
|
4
|
+
module Comparability
|
5
|
+
module Comparators
|
6
|
+
module FactoryMethods
|
7
|
+
|
8
|
+
def create(comparison = nil, options = {}, &block)
|
9
|
+
comparison ||= block
|
10
|
+
comparator =
|
11
|
+
case comparison
|
12
|
+
when Symbol
|
13
|
+
create_from_symbol(comparison)
|
14
|
+
when Proc
|
15
|
+
create_from_proc(comparison)
|
16
|
+
when ->(_) { _.respond_to?(:to_proc) }
|
17
|
+
create_from_proc(comparison.to_proc)
|
18
|
+
else
|
19
|
+
raise ArgumentError, 'invalid comparison'
|
20
|
+
end
|
21
|
+
apply_options(comparator, options)
|
22
|
+
end
|
23
|
+
|
24
|
+
# @param comparisons [Array]
|
25
|
+
# each comparison should be either Comparison instance or argument(s) accepted by #create
|
26
|
+
def chain(*comparisons)
|
27
|
+
comparators = comparisons.map do |comparison_or_comparator|
|
28
|
+
case comparison_or_comparator
|
29
|
+
when Comparator
|
30
|
+
comparison_or_comparator
|
31
|
+
else
|
32
|
+
create(*comparison_or_comparator)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
ComparatorChain.new(comparators)
|
36
|
+
end
|
37
|
+
alias_method :[], :chain
|
38
|
+
|
39
|
+
# @param priority [Symbol] :first or :last
|
40
|
+
def prioritize_nil(priority)
|
41
|
+
NilComparator.with_nil_priority(priority)
|
42
|
+
end
|
43
|
+
|
44
|
+
# @option options [true] :reverse
|
45
|
+
def natural_order(options = {})
|
46
|
+
@_natural_order ||= Comparator.new
|
47
|
+
if options[:reverse]
|
48
|
+
@_reverse_natural_order ||= reverse(@_natural_order)
|
49
|
+
else
|
50
|
+
@_natural_order
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# @param comparator [Comparator]
|
55
|
+
def reverse(comparator)
|
56
|
+
ReverseWrapperComparator.wrap(comparator)
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def create_from_symbol(attr)
|
62
|
+
AttributeValueComparator.new(attr)
|
63
|
+
end
|
64
|
+
|
65
|
+
def create_from_proc(proc)
|
66
|
+
case proc.arity
|
67
|
+
when 1
|
68
|
+
ValueExtractorComparator.new(proc)
|
69
|
+
when 2
|
70
|
+
ProcComparator.new(proc)
|
71
|
+
else
|
72
|
+
raise ArgumentError, 'invalid comparison'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def apply_options(comparator, options)
|
77
|
+
nil_value_priority = options.fetch(:nil, nil)
|
78
|
+
reversing = options.fetch(:reverse, false)
|
79
|
+
|
80
|
+
if nil_value_priority
|
81
|
+
raise ArgumentError unless comparator.respond_to?(:nil_value_priority=)
|
82
|
+
if reversing
|
83
|
+
# value comparison should be reversed, but not the nil priority
|
84
|
+
case nil_value_priority
|
85
|
+
when :first
|
86
|
+
nil_value_priority = :last
|
87
|
+
when :last
|
88
|
+
nil_value_priority = :first
|
89
|
+
end
|
90
|
+
end
|
91
|
+
comparator.nil_value_priority = nil_value_priority
|
92
|
+
end
|
93
|
+
|
94
|
+
if reversing
|
95
|
+
comparator = reverse(comparator)
|
96
|
+
end
|
97
|
+
|
98
|
+
comparator
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
|
5
|
+
module Comparability
|
6
|
+
module Comparators
|
7
|
+
module NilComparator
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
def with_nil_priority(priority)
|
12
|
+
raise ArgumentError unless %[first last].include?(priority.to_s)
|
13
|
+
public_send("nil_#{priority}")
|
14
|
+
end
|
15
|
+
|
16
|
+
def nil_first
|
17
|
+
@_nil_first ||= ReverseWrapperComparator.wrap(NilLastComparator.instance)
|
18
|
+
end
|
19
|
+
|
20
|
+
def nil_last
|
21
|
+
NilLastComparator.instance
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
class NilLastComparator < Comparator
|
27
|
+
include Singleton
|
28
|
+
|
29
|
+
def compare(me, other)
|
30
|
+
if me.nil? && other.nil?
|
31
|
+
0
|
32
|
+
elsif me.nil?
|
33
|
+
1
|
34
|
+
elsif other.nil?
|
35
|
+
-1
|
36
|
+
else
|
37
|
+
0
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Comparability
|
4
|
+
module Comparators
|
5
|
+
class ProcComparator < Comparator
|
6
|
+
|
7
|
+
def initialize(comparison)
|
8
|
+
raise ArgumentError unless comparison.is_a?(Proc) && comparison.arity == 2
|
9
|
+
self.singleton_class.send(:define_method, :compare, &comparison)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require_relative 'wrapper_comparator'
|
4
|
+
|
5
|
+
module Comparability
|
6
|
+
module Comparators
|
7
|
+
class ReverseWrapperComparator < WrapperComparator
|
8
|
+
|
9
|
+
def compare(me, other)
|
10
|
+
reverse(wrapped_compare(me, other))
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def reverse(comparison_result)
|
16
|
+
if comparison_result.nil? || comparison_result.zero?
|
17
|
+
comparison_result
|
18
|
+
else
|
19
|
+
-comparison_result
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require_relative 'nil_comparator'
|
4
|
+
|
5
|
+
module Comparability
|
6
|
+
module Comparators
|
7
|
+
class ValueComparator < Comparator
|
8
|
+
|
9
|
+
def compare(me, other)
|
10
|
+
me_value = extract_value(me)
|
11
|
+
other_value = extract_other_value(me, other)
|
12
|
+
|
13
|
+
if nil_value_priority
|
14
|
+
nil_result = NilComparator.with_nil_priority(nil_value_priority).compare(me_value, other_value)
|
15
|
+
return nil_result if nil_result && nil_result.nonzero?
|
16
|
+
end
|
17
|
+
|
18
|
+
me_value <=> other_value
|
19
|
+
end
|
20
|
+
|
21
|
+
def nil_value_priority=(priority)
|
22
|
+
raise ArgumentError unless [nil, :first, :last].include?(priority)
|
23
|
+
@nil_value_priority = priority
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_reader :nil_value_priority
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def extract_value(me)
|
31
|
+
raise 'abstract'
|
32
|
+
end
|
33
|
+
|
34
|
+
def extract_other_value(me, obj)
|
35
|
+
extract_value(obj)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require_relative 'value_comparator'
|
4
|
+
|
5
|
+
module Comparability
|
6
|
+
module Comparators
|
7
|
+
class ValueExtractorComparator < ValueComparator
|
8
|
+
|
9
|
+
def initialize(value_extractor)
|
10
|
+
raise ArgumentError unless value_extractor.is_a?(Proc) && value_extractor.arity == 1
|
11
|
+
@value_extractor = value_extractor
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
attr_reader :value_extractor
|
17
|
+
|
18
|
+
def extract_value(obj)
|
19
|
+
value_extractor.(obj)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Comparability
|
4
|
+
module Comparators
|
5
|
+
class WrapperComparator < Comparator
|
6
|
+
|
7
|
+
class << self
|
8
|
+
alias_method :wrap, :new
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(comparator)
|
12
|
+
raise ArgumentError unless comparator.is_a?(Comparator)
|
13
|
+
@wrapped = comparator
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
attr_reader :wrapped
|
19
|
+
|
20
|
+
def wrapped_compare(me, other)
|
21
|
+
wrapped.compare(me, other)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: comparability
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ippei Ukai
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-07-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description:
|
42
|
+
email:
|
43
|
+
- ippei@users.sourceforge.net
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- ".gitignore"
|
49
|
+
- Gemfile
|
50
|
+
- LICENSE.txt
|
51
|
+
- README.md
|
52
|
+
- Rakefile
|
53
|
+
- comparability.gemspec
|
54
|
+
- lib/comparability.rb
|
55
|
+
- lib/comparability/comparable_by.rb
|
56
|
+
- lib/comparability/comparator.rb
|
57
|
+
- lib/comparability/comparators/attribute_value_comparator.rb
|
58
|
+
- lib/comparability/comparators/comparator_chain.rb
|
59
|
+
- lib/comparability/comparators/factory_methods.rb
|
60
|
+
- lib/comparability/comparators/nil_comparator.rb
|
61
|
+
- lib/comparability/comparators/proc_comparator.rb
|
62
|
+
- lib/comparability/comparators/reverse_wrapper_comparator.rb
|
63
|
+
- lib/comparability/comparators/value_comparator.rb
|
64
|
+
- lib/comparability/comparators/value_extractor_comparator.rb
|
65
|
+
- lib/comparability/comparators/wrapper_comparator.rb
|
66
|
+
- lib/comparability/version.rb
|
67
|
+
homepage: http://github.com/ippeiukai/comparability
|
68
|
+
licenses:
|
69
|
+
- MIT
|
70
|
+
metadata: {}
|
71
|
+
post_install_message:
|
72
|
+
rdoc_options: []
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
requirements: []
|
86
|
+
rubyforge_project:
|
87
|
+
rubygems_version: 2.2.2
|
88
|
+
signing_key:
|
89
|
+
specification_version: 4
|
90
|
+
summary: Provides Comparator and declarative definition of comparison operator.
|
91
|
+
test_files: []
|