boundy 0.3.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.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/lib/boundy.rb +19 -0
  3. data/lib/boundy/bound.rb +65 -0
  4. data/lib/boundy/bound/comparator.rb +67 -0
  5. data/lib/boundy/bound/constrainer.rb +29 -0
  6. data/lib/boundy/bound/infinite.rb +46 -0
  7. data/lib/boundy/bound/infinite/above.rb +12 -0
  8. data/lib/boundy/bound/infinite/below.rb +13 -0
  9. data/lib/boundy/comparator.rb +19 -0
  10. data/lib/boundy/comparators.rb +28 -0
  11. data/lib/boundy/domain.rb +115 -0
  12. data/lib/boundy/domain/anterior.rb +45 -0
  13. data/lib/boundy/domain/builder.rb +31 -0
  14. data/lib/boundy/domain/comparator.rb +26 -0
  15. data/lib/boundy/domain/constrainer.rb +21 -0
  16. data/lib/boundy/domain/finite.rb +64 -0
  17. data/lib/boundy/domain/posterior.rb +43 -0
  18. data/lib/boundy/formatter.rb +9 -0
  19. data/lib/boundy/formatter/sql.rb +26 -0
  20. data/lib/boundy/formatter/sql/domain.rb +20 -0
  21. data/lib/boundy/formatter/sql/domain/plugin.rb +22 -0
  22. data/lib/boundy/formatter/sql/factory.rb +14 -0
  23. data/lib/boundy/formatter/sql/plugin.rb +38 -0
  24. data/lib/boundy/formatters/bound.rb +16 -0
  25. data/lib/boundy/formatters/domain.rb +12 -0
  26. data/lib/boundy/formatters/fixnum.rb +20 -0
  27. data/lib/boundy/formatters/sql/bound.rb +22 -0
  28. data/lib/boundy/formatters/sql/domain.rb +28 -0
  29. data/lib/boundy/formatters/sql/domain/anterior.rb +23 -0
  30. data/lib/boundy/formatters/sql/domain/finite.rb +24 -0
  31. data/lib/boundy/formatters/sql/domain/posterior.rb +23 -0
  32. data/lib/boundy/formatters/time.rb +42 -0
  33. data/lib/boundy/range/comparator.rb +38 -0
  34. data/lib/boundy/range/constrainer.rb +17 -0
  35. data/lib/boundy/time/comparator.rb +37 -0
  36. data/test/integration/boundy_test.rb +37 -0
  37. data/test/integration/domain_test.rb +18 -0
  38. data/test/integration/formatter/sql_test.rb +21 -0
  39. data/test/integration/test_helper.rb +14 -0
  40. data/test/unit/boundy/bound/comparator_test.rb +37 -0
  41. data/test/unit/boundy/bound/constrainer_test.rb +123 -0
  42. data/test/unit/boundy/bound/infinite/above_test.rb +36 -0
  43. data/test/unit/boundy/bound/infinite/below_test.rb +36 -0
  44. data/test/unit/boundy/bound/infinite_test.rb +0 -0
  45. data/test/unit/boundy/bound_test.rb +86 -0
  46. data/test/unit/boundy/comparator_test.rb +0 -0
  47. data/test/unit/boundy/domain/anterior_test.rb +103 -0
  48. data/test/unit/boundy/domain/comparator_test.rb +75 -0
  49. data/test/unit/boundy/domain/constrainer_test.rb +11 -0
  50. data/test/unit/boundy/domain/posterior_test.rb +75 -0
  51. data/test/unit/boundy/domain_test.rb +50 -0
  52. data/test/unit/boundy/formatter/sql/domain/plugin_test.rb +16 -0
  53. data/test/unit/boundy/formatter/sql/plugin_test.rb +50 -0
  54. data/test/unit/boundy/formatter/sql_test.rb +26 -0
  55. data/test/unit/boundy/formatters/bound_test.rb +43 -0
  56. data/test/unit/boundy/formatters/domain_test.rb +12 -0
  57. data/test/unit/boundy/formatters/sql/domain/anterior_test.rb +29 -0
  58. data/test/unit/boundy/formatters/sql/domain/finite_test.rb +35 -0
  59. data/test/unit/boundy/formatters/sql/domain/posterior_test.rb +30 -0
  60. data/test/unit/boundy/formatters/time_test.rb +27 -0
  61. data/test/unit/boundy/range/comparator_test.rb +44 -0
  62. data/test/unit/boundy/range/constrainer_test.rb +11 -0
  63. data/test/unit/boundy/time/comparator_test.rb +40 -0
  64. data/test/unit/test_helper.rb +14 -0
  65. metadata +154 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 55bb89b47f6477f182a1e2f5dc6409a386a3593c
4
+ data.tar.gz: e54945d291b401d501003dacce33a5696dae01d2
5
+ SHA512:
6
+ metadata.gz: 80d51de835f5509772835a640a17c0c98b8c8d010cfcaf65ab22ebf54b61d1b97f2415898424092365414c01e167124fee92cefe2a824ae8124baee91989b640
7
+ data.tar.gz: 775bb5bdfaedf3247ab54a4e39ad23a6b94b70a7dcbd45ab1a6f5037a9f4046d76af55d41d3a72c06b94e58a58954e8447bf9e59c2c9371ab5d3180a8f9c6b45
data/lib/boundy.rb ADDED
@@ -0,0 +1,19 @@
1
+ module Boundy
2
+
3
+ class << self
4
+ def logger
5
+ return @logger if @logger
6
+
7
+ @logger = Logger.new(STDOUT)
8
+ @logger.formatter = proc { |severity, datetime, progname, msg|
9
+ "[#{datetime}, #{severity}] #{msg}\n"
10
+ }
11
+ @logger
12
+ end
13
+
14
+ def logger=(logger)
15
+ @logger = logger
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,65 @@
1
+ require 'boundy/bound'
2
+ require 'boundy/bound/infinite'
3
+ require 'boundy/comparators'
4
+
5
+ #require 'manacle/proxy'
6
+
7
+ module Boundy
8
+ class Bound
9
+ def initialize(datum)
10
+ if datum.class <= self.class || datum.class < Boundy::Bound::Infinite
11
+ raise "Datum is a Bound already!"
12
+ end
13
+
14
+ if datum.nil?
15
+ raise "Datum passed is nil!"
16
+ end
17
+ @datum = datum
18
+ end
19
+
20
+ def after?(subject)
21
+ Comparators.comparator(self, subject).after?
22
+ end
23
+
24
+ def before?(subject)
25
+ Comparators.comparator(self, subject).before?
26
+ end
27
+
28
+ def within?(subject)
29
+ Comparators.comparator(self, subject).within?
30
+ end
31
+
32
+ def finite?
33
+ true
34
+ end
35
+
36
+ def infinite?
37
+ false
38
+ end
39
+
40
+ def inspect
41
+ "#<#{self.class.name} bounded at #{@datum.inspect}>"
42
+ end
43
+
44
+ def comparator
45
+ Boundy::Bound::Comparator
46
+ end
47
+
48
+ attr_reader :datum
49
+
50
+ include Comparable
51
+
52
+ def <=>(other)
53
+ case other
54
+ when Boundy::Bound::Infinite::Above
55
+ (other <=> self) * -1
56
+ when Boundy::Bound::Infinite::Below
57
+ (other <=> self) * -1
58
+ when Boundy::Bound
59
+ datum <=> other.datum
60
+ else
61
+ raise "Can not compare a Bound to a #{other.class}"
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,67 @@
1
+ require 'boundy/bound'
2
+ require 'boundy/bound/infinite'
3
+
4
+ module Boundy
5
+ class Bound
6
+ class Comparator
7
+ def initialize(a, b)
8
+ @a = a
9
+ @b = b
10
+ end
11
+
12
+ Bound = Boundy::Bound
13
+
14
+ COMPARISONS = {
15
+ Bound::Infinite::Above => {
16
+ Bound::Infinite::Above => :equal,
17
+ Bound::Infinite::Below => :left,
18
+ Bound => :left
19
+ },
20
+ Bound::Infinite::Below => {
21
+ Bound::Infinite::Above => :right,
22
+ Bound::Infinite::Below => :equal,
23
+ Bound => :right
24
+ },
25
+ Bound => {
26
+ Bound::Infinite::Above => :right,
27
+ Bound::Infinite::Below => :left
28
+ }
29
+ }
30
+
31
+ def before?
32
+ compare == :left
33
+ end
34
+
35
+ def after?
36
+ compare == :right
37
+ end
38
+
39
+ def within?
40
+ compare == :equal
41
+ end
42
+
43
+ def compare
44
+ result = nil
45
+ if COMPARISONS.has_key?(@a.class)
46
+ part_comp = COMPARISONS[@a.class]
47
+ if part_comp.has_key?(@b.class)
48
+ result = part_comp[@b.class]
49
+ end
50
+ end
51
+
52
+ map = {
53
+ -1 => :right,
54
+ 0 => :equal,
55
+ 1 => :left
56
+ }
57
+
58
+ if result.nil?
59
+ map[@a.datum <=> @b.datum]
60
+ else
61
+ result
62
+ end
63
+
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,29 @@
1
+ require 'boundy/bound/comparator'
2
+
3
+ module Boundy
4
+ class Bound
5
+ class Constrainer
6
+ def initialize(a, b)
7
+ @a = a
8
+ @b = b
9
+ @comparator = Boundy::Bound::Comparator.new(a,b)
10
+ end
11
+
12
+ def max
13
+ if @comparator.compare == :left
14
+ @a
15
+ else
16
+ @b
17
+ end
18
+ end
19
+
20
+ def min
21
+ if @comparator.compare == :right
22
+ @a
23
+ else
24
+ @b
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,46 @@
1
+ module Boundy
2
+ # An Anterior domain date has a beginning, but no end -- hence, is
3
+ # anterior-domain.
4
+ class Bound
5
+ class Infinite
6
+ def after?(date_range)
7
+ false
8
+ end
9
+
10
+ def before?(date_range)
11
+ false
12
+ end
13
+
14
+ def within?(date_range)
15
+ true
16
+ end
17
+
18
+ def in_time_zone(tz)
19
+ self
20
+ end
21
+
22
+ def to_midnight
23
+ self
24
+ end
25
+
26
+ def date
27
+ nil
28
+ end
29
+
30
+ def finite?
31
+ false
32
+ end
33
+
34
+ def infinite?
35
+ true
36
+ end
37
+
38
+ def <=>(other)
39
+ raise ""
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ require 'boundy/bound/infinite/above'
46
+ require 'boundy/bound/infinite/below'
@@ -0,0 +1,12 @@
1
+ module Boundy
2
+ class Bound
3
+ class Infinite
4
+ class Above < Infinite
5
+ include Comparable
6
+ def <=>(other)
7
+ 1
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ module Boundy
2
+ class Bound
3
+ class Infinite
4
+ class Below < Infinite
5
+ include Comparable
6
+ def <=>(other)
7
+ -1
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,19 @@
1
+ require 'boundy/comparators'
2
+
3
+ module Boundy
4
+ module Comparator
5
+ def self.included(base)
6
+ types = if base.respond_to?(:type)
7
+ [base.type]
8
+ elsif base.respond_to?(:types)
9
+ base.types
10
+ else
11
+ []
12
+ end
13
+
14
+ types.each do |t|
15
+ Boundy::Comparators.add(t, base)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,28 @@
1
+ require 'set'
2
+
3
+ require 'punchout'
4
+ require 'punchout/matcher/class'
5
+
6
+ module Boundy
7
+ module Comparators
8
+ extend Punchout::Punchable
9
+
10
+
11
+ def self.add(type, comparator)
12
+ matchable = Punchout::Matcher::Klass.new(type).punches(comparator)
13
+ puncher.add(matchable)
14
+ end
15
+
16
+ def self.comparator(datum,subject)
17
+ comparator = if subject.respond_to?(:comparator)
18
+ subject.comparator
19
+ else
20
+ puncher.punch(subject.class)
21
+ end
22
+
23
+ comparator.new(datum, subject)
24
+ rescue
25
+ raise "I can't compare myself to a #{subject.class}: #{subject.inspect}"
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,115 @@
1
+ require 'boundy/bound'
2
+
3
+ require 'boundy/domain/comparator'
4
+ require 'boundy/domain/constrainer'
5
+ require 'boundy/range/constrainer'
6
+
7
+ module Boundy
8
+ module Domain
9
+ module Plugin
10
+ def self.included(base)
11
+ Domain.builder.add(base)
12
+ base.instance_eval do
13
+ include InstanceMethods
14
+ attr_reader :from
15
+ attr_reader :to
16
+ end
17
+ end
18
+ end
19
+
20
+ class Builder
21
+ def initialize
22
+ @klasses = {}
23
+ end
24
+
25
+ def add(domain_klass)
26
+ builder = domain_klass.builder
27
+
28
+ bound_types = builder[:bounds]
29
+ builder_method = builder[:builder]
30
+
31
+ @klasses[bound_types] = builder_method
32
+ end
33
+
34
+ def build(a,b)
35
+ builder = @klasses[{from: a.class, to: b.class}]
36
+
37
+ if builder.nil?
38
+ raise "Could not find class for #{a.class} and #{b.class}"
39
+ end
40
+
41
+ builder.call(a,b)
42
+ end
43
+ end
44
+
45
+
46
+ def self.builder
47
+ @builder ||= Builder.new
48
+ end
49
+
50
+
51
+ def self.translate(bound)
52
+ if bound.class <= Boundy::Bound or bound.class < Boundy::Bound::Infinite
53
+ bound
54
+ else
55
+ Boundy::Bound.new(bound)
56
+ end
57
+ end
58
+
59
+ def self.new(b,e=nil)
60
+ if b.class <= Boundy::Domain::Plugin
61
+ b
62
+ else
63
+ b = translate(b)
64
+ e = translate(e)
65
+
66
+ built = builder.build(b,e)
67
+ unless built.class < Plugin
68
+ raise
69
+ end
70
+ built
71
+ end
72
+ end
73
+
74
+ module InstanceMethods
75
+
76
+ def within?(subject)
77
+ @from.within?(subject) || @from.after?(subject) and
78
+ @to.within?(subject) || @to.before?(subject)
79
+ end
80
+
81
+ def joinable?(subject)
82
+ strictly_earlier?(subject) || strictly_later?(subject)
83
+ end
84
+
85
+ def constrain_to(subject)
86
+ constrainer(subject).constrain
87
+ end
88
+
89
+ def constrainer(subject)
90
+ if subject.class == ::Range
91
+ Boundy::Range::Constrainer.new(self, subject)
92
+ elsif subject.class < Boundy::Domain::Plugin
93
+ Boundy::Domain::Constrainer.new(self, subject)
94
+ else
95
+ raise "I can't constrain myself against a #{subject.class}"
96
+ end
97
+ end
98
+
99
+ def comparator
100
+ Boundy::Domain::Comparator
101
+ end
102
+
103
+ def format(formatter)
104
+ if from.finite?
105
+ elsif to.finite?
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+
113
+ require 'boundy/domain/anterior'
114
+ require 'boundy/domain/finite'
115
+ require 'boundy/domain/posterior'
@@ -0,0 +1,45 @@
1
+ require 'boundy/domain'
2
+ require 'boundy/bound'
3
+ require 'boundy/bound/infinite/above'
4
+
5
+ module Boundy
6
+ module Domain
7
+ # An Anterior domain datum has a beginning, but no end -- hence, is
8
+ # anterior-domain.
9
+ class Anterior
10
+ def self.builder
11
+ {
12
+ bounds: {
13
+ from: Boundy::Bound,
14
+ to: Boundy::Bound::Infinite::Above
15
+ },
16
+ builder: Proc.new {|b,e| self.new(b) }
17
+ }
18
+ end
19
+
20
+ include Domain::Plugin
21
+
22
+ def initialize(datum)
23
+ if datum.nil?
24
+ raise
25
+ end
26
+
27
+ @from = case datum
28
+ when Boundy::Bound
29
+ datum
30
+ else
31
+ Boundy::Bound.new(datum)
32
+ end
33
+ @to = Boundy::Bound::Infinite::Above.new
34
+ end
35
+
36
+ def cute
37
+ "[#{@from.datum}, infinity]"
38
+ end
39
+
40
+ def inspect
41
+ "#<#{self.class.name} bounded below by #{@from.inspect}>"
42
+ end
43
+ end
44
+ end
45
+ end