attr_comparable 0.0.1

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.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ .idea
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ # ruby '1.8.7'
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in attr_default.gemspec
6
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,18 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ attr_comparable (0.0.1)
5
+ minitest
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ minitest (5.0.6)
11
+ rake (10.1.0)
12
+
13
+ PLATFORMS
14
+ ruby
15
+
16
+ DEPENDENCIES
17
+ attr_comparable!
18
+ rake (>= 0.9)
data/README.md ADDED
@@ -0,0 +1,75 @@
1
+ attr_comparable gem
2
+ ===================
3
+
4
+ Mix-in to make a class Comparable, declaratively
5
+ ------------------------------------------------
6
+
7
+ Use `attr_compare <attribute list>`
8
+ to declare the attributes which should be compared, in their order of precedence.
9
+ Attributes may be nil. nil attributes sort earlier than non-nil to match the SQL behavior for NULL.
10
+
11
+ Example without AttrComparable
12
+ ------------------------------
13
+
14
+ Consider this value class that holds full names:
15
+ ```ruby
16
+ class FullName
17
+ include Comparable
18
+
19
+ attr_reader :first, :middle, :last, :suffix
20
+
21
+ def initialize(first, middle, last, suffix = nil)
22
+ @first = first
23
+ @middle = middle
24
+ @last = last
25
+ @suffix = suffix
26
+ end
27
+
28
+ def <=>(other)
29
+ (last <=> other.last).nonzero? ||
30
+ (first <=> other.first).nonzero? ||
31
+ (middle <=> other.middle).nonzero? ||
32
+ suffix <=> other.suffix
33
+ end
34
+ end
35
+ ```
36
+ You can see that the `<=>` method isn't very DRY, and as shown it doesn't even work with `nil`.
37
+ (That's just too ugly to show.)
38
+
39
+ Example with AttrComparable
40
+ ---------------------------
41
+ Here it is using the gem. Only the 2 lines with the comments are needed.
42
+ ```ruby
43
+ require 'attr_comparable'
44
+ require 'active_support'
45
+
46
+ class FullName
47
+ include AttrComparable # AttrComparable automatically includes Comparable
48
+
49
+ attr_compare :last, :first, :middle, :suffix # will be compared in this precedence order
50
+ attr_reader :first, :middle, :last, :suffix
51
+
52
+ def initialize(first, middle, last, suffix = nil)
53
+ @first = first
54
+ @middle = middle
55
+ @last = last
56
+ @suffix = suffix
57
+ end
58
+
59
+ def to_s
60
+ no_suffix = [first.presence, middle.presence, last.presence].compact.join(' ')
61
+ [no_suffix, suffix.presence].compact.join(', ')
62
+ end
63
+ end
64
+ ```
65
+ Example Usage
66
+ ---------------------------
67
+ ```ruby
68
+ >> mom = FullName.new("Kathy", nil, "Doe")
69
+ >> dad = FullName.new("John", "Q.", "Public")
70
+ >> junior = FullName.new("John", "Q.", "Public", "Jr.")
71
+ >> junior > dad
72
+ => true
73
+ >> [mom, dad, junior].sort.map &:to_s
74
+ => ["Kathy Doe", "John Q. Public", "John Q. Public, Jr."]
75
+ ```
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ task :default => :test
5
+
6
+ desc "Run unit tests."
7
+ task :test do
8
+ ruby "test/attr_comparable_test.rb"
9
+ end
@@ -0,0 +1,18 @@
1
+ require File.expand_path('../lib/attr_comparable/version', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.add_dependency 'minitest' # Included in Ruby 1.9, but we want the latest.
5
+ gem.add_development_dependency 'rake', '>=0.9'
6
+
7
+ gem.authors = ["Colin Kelley"]
8
+ gem.email = ["colindkelley@gmail.com"]
9
+ gem.description = %q{AttrComparable}
10
+ gem.summary = %q{Mix-in to make a value class Comparable. Simply declare the order of attributes to compare and the <=> (as needed by Comparable) is generated for you, including support for nil. Includes Comparable.}
11
+ gem.homepage = "https://github.com/RingRevenue/attr_comparable"
12
+
13
+ gem.files = `git ls-files`.split($\)
14
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
15
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/.*\.rb})
16
+ gem.name = "attr_comparable"
17
+ gem.version = AttrComparable::VERSION
18
+ end
@@ -0,0 +1,44 @@
1
+ #
2
+ # Mix-in to make a class Comparable
3
+ #
4
+ # Use attr_comparabie <attribute list>
5
+ # to declare the attributes which should be compared, and the order they should be
6
+ # Attributes may be nil; nil attributes sort earlier than non-nil to match the SQL convention
7
+ #
8
+ module AttrComparable
9
+ include Comparable
10
+
11
+ module ClassMethods
12
+ # like <=> but handles nil values
13
+ # when equal, returns nil rather than 0 so the caller can || together
14
+ def compare_with_nil(left, right)
15
+ if left.nil?
16
+ if right.nil?
17
+ nil
18
+ else
19
+ -1
20
+ end
21
+ elsif right.nil?
22
+ 1
23
+ else
24
+ (left <=> right).nonzero?
25
+ end
26
+ end
27
+
28
+ def attr_compare(*attributes)
29
+ attributes = attributes.flatten
30
+ class_eval <<-EOS
31
+ def <=>(rhs)
32
+ #{attributes.map do |attribute|
33
+ "self.class.compare_with_nil(self.#{attribute}, rhs.#{attribute})"
34
+ end.join(" || ")
35
+ } || 0
36
+ end
37
+ EOS
38
+ end
39
+ end
40
+
41
+ def self.included(base_class)
42
+ base_class.extend ClassMethods
43
+ end
44
+ end
@@ -0,0 +1,3 @@
1
+ module AttrComparable
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,107 @@
1
+ require File.expand_path('../../lib/attr_comparable', __FILE__)
2
+ require 'bundler'
3
+ Bundler.require(:default)
4
+ require 'minitest/autorun'
5
+
6
+
7
+ class ComparableTestOneParameter
8
+ include AttrComparable
9
+ attr_reader :last_name
10
+ attr_compare :last_name
11
+
12
+ def initialize(last_name)
13
+ @last_name = last_name
14
+ end
15
+ end
16
+
17
+ class ComparableTestManyParameters
18
+ include AttrComparable
19
+ attr_reader :last_name, :first_name
20
+ attr_compare :last_name, :first_name
21
+
22
+ def initialize(last_name, first_name)
23
+ @last_name = last_name
24
+ @first_name = first_name
25
+ end
26
+ end
27
+
28
+
29
+ describe 'AttrComparable' do
30
+ describe "one parameter" do
31
+ before do
32
+ @d1 = ComparableTestOneParameter.new('Jones')
33
+ @d2 = ComparableTestOneParameter.new('Jones')
34
+ @d3 = ComparableTestOneParameter.new('Kelley')
35
+ end
36
+
37
+ it "should define <=>" do
38
+ assert_equal 0, @d1 <=> @d2
39
+ assert_equal -1, @d1 <=> @d3
40
+ assert_equal 1, @d3 <=> @d1
41
+ end
42
+
43
+ it "should define relative operators like Comparable" do
44
+ assert @d1.is_a?(Comparable)
45
+ assert @d1 < @d3
46
+ assert @d3 >= @d2
47
+ assert @d1 == @d2
48
+ assert @d2 != @d3
49
+ end
50
+ end
51
+
52
+ describe "many parameters" do
53
+ before do
54
+ @d1 = ComparableTestManyParameters.new('Jones', 'S')
55
+ @d2 = ComparableTestManyParameters.new('Jones', 'T')
56
+ @d3 = ComparableTestManyParameters.new('Jones', 'S')
57
+ @d4 = ComparableTestManyParameters.new('Kelley', 'C')
58
+ end
59
+
60
+ it "should define <=>" do
61
+ assert_equal 0, @d1 <=> @d3
62
+ assert_equal -1, @d1 <=> @d2
63
+ assert_equal 1, @d4 <=> @d1
64
+ end
65
+
66
+ it "should be Comparable" do
67
+ assert @d1.is_a?(Comparable)
68
+ end
69
+
70
+ it "should define relative operators from Comparable" do
71
+ assert @d1 < @d2
72
+ assert @d2 >= @d3
73
+ assert @d1 == @d3
74
+ assert @d2 != @d3
75
+ end
76
+ end
77
+
78
+ it "should be able to compare with nil" do
79
+ assert_equal nil, ComparableTestManyParameters.compare_with_nil(nil, nil)
80
+ assert_equal -1, ComparableTestManyParameters.compare_with_nil(nil, 1)
81
+ assert_equal 1, ComparableTestOneParameter.compare_with_nil(1, nil)
82
+ assert_equal 1, ComparableTestOneParameter.compare_with_nil("dog", "cat")
83
+ end
84
+
85
+ describe "many parameters with nil" do
86
+ before do # sort order
87
+ @d1 = ComparableTestManyParameters.new(nil, 'S') # 1
88
+ @d2 = ComparableTestManyParameters.new('Jones', nil) # 2
89
+ @d3 = ComparableTestManyParameters.new(nil, nil) # 0
90
+ @d4 = ComparableTestManyParameters.new('Jones', 'S') # 3
91
+ end
92
+
93
+ it "should define <=> with nil first" do
94
+ assert_equal 0, @d1 <=> @d1
95
+ assert_equal 0, @d3 <=> @d3
96
+ assert_equal -1, @d1 <=> @d2
97
+ assert_equal 1, @d2 <=> @d3
98
+ assert_equal -1, @d2 <=> @d4
99
+ end
100
+
101
+ it "should define relative operators from Comparable" do
102
+ assert @d1 == @d1
103
+ assert @d2 > @d3
104
+ assert @d2 != @d3
105
+ end
106
+ end
107
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: attr_comparable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Colin Kelley
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-08-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: minitest
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0.9'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0.9'
46
+ description: AttrComparable
47
+ email:
48
+ - colindkelley@gmail.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
54
+ - Gemfile
55
+ - Gemfile.lock
56
+ - README.md
57
+ - Rakefile
58
+ - attr_comparable.gemspec
59
+ - lib/attr_comparable.rb
60
+ - lib/attr_comparable/version.rb
61
+ - test/attr_comparable_test.rb
62
+ homepage: https://github.com/RingRevenue/attr_comparable
63
+ licenses: []
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ segments:
75
+ - 0
76
+ hash: 4162700180279227236
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ segments:
84
+ - 0
85
+ hash: 4162700180279227236
86
+ requirements: []
87
+ rubyforge_project:
88
+ rubygems_version: 1.8.25
89
+ signing_key:
90
+ specification_version: 3
91
+ summary: Mix-in to make a value class Comparable. Simply declare the order of attributes
92
+ to compare and the <=> (as needed by Comparable) is generated for you, including
93
+ support for nil. Includes Comparable.
94
+ test_files:
95
+ - test/attr_comparable_test.rb