facets 2.9.0.pre.1 → 2.9.0.pre.2

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 (107) hide show
  1. data/AUTHORS +1 -0
  2. data/COPYING +1 -2
  3. data/HISTORY.rdoc +16 -8
  4. data/lib/core/facets/hash/subset.rb +24 -0
  5. data/lib/core/facets/hash/zip.rb +18 -0
  6. data/lib/core/facets/kernel/try.rb +3 -3
  7. data/lib/core/facets/module/home.rb +90 -0
  8. data/lib/core/facets/module/homename.rb +1 -0
  9. data/lib/core/facets/module/housing.rb +1 -0
  10. data/lib/core/facets/module/modname.rb +1 -22
  11. data/lib/core/facets/na.rb +11 -5
  12. data/lib/core/facets/object/clone.rb +1 -0
  13. data/lib/core/facets/{kernel/try_dup.rb → object/dup.rb} +41 -35
  14. data/lib/core/facets/{kernel → object}/object_state.rb +15 -18
  15. data/lib/core/facets/object/replace.rb +43 -0
  16. data/lib/core/facets/object/try_dup.rb +1 -0
  17. data/lib/core/facets/string/cleanlines.rb +2 -0
  18. data/lib/core/facets/time/ago.rb +1 -1
  19. data/lib/core/facets/time/in.rb +1 -93
  20. data/lib/core/facets/time/less.rb +1 -0
  21. data/lib/core/facets/time/shift.rb +95 -0
  22. data/lib/more/facets/interval.rb +284 -0
  23. data/lib/more/facets/math.rb +6 -0
  24. data/lib/more/facets/math/abs.rb +8 -0
  25. data/lib/more/facets/math/acot.rb +8 -0
  26. data/lib/more/facets/math/acoth.rb +8 -0
  27. data/lib/more/facets/math/acsc.rb +8 -0
  28. data/lib/more/facets/math/acsch.rb +8 -0
  29. data/lib/more/facets/math/amd.rb +17 -0
  30. data/lib/more/facets/math/approx_equal.rb +15 -0
  31. data/lib/more/facets/math/asec.rb +8 -0
  32. data/lib/more/facets/math/asech.rb +8 -0
  33. data/lib/more/facets/math/atkinson_index.rb +16 -0
  34. data/lib/more/facets/math/beta.rb +9 -0
  35. data/lib/more/facets/math/cdf.rb +10 -0
  36. data/lib/more/facets/math/ceil.rb +8 -0
  37. data/lib/more/facets/math/cot.rb +8 -0
  38. data/lib/more/facets/math/coth.rb +8 -0
  39. data/lib/more/facets/math/csc.rb +8 -0
  40. data/lib/more/facets/math/csch.rb +8 -0
  41. data/lib/more/facets/math/delta.rb +8 -0
  42. data/lib/more/facets/math/epsilon.rb +21 -0
  43. data/lib/more/facets/math/exp10.rb +8 -0
  44. data/lib/more/facets/math/exp2.rb +8 -0
  45. data/lib/more/facets/math/factorial.rb +37 -0
  46. data/lib/more/facets/math/floor.rb +8 -0
  47. data/lib/more/facets/math/gamma.rb +12 -0
  48. data/lib/more/facets/math/gcd.rb +23 -0
  49. data/lib/more/facets/math/gini_coefficient.rb +33 -0
  50. data/lib/more/facets/math/kldivergence.rb +19 -0
  51. data/lib/more/facets/math/lcm.rb +15 -0
  52. data/lib/more/facets/math/lgamma.rb +21 -0
  53. data/lib/more/facets/math/linsolve.rb +10 -0
  54. data/lib/more/facets/math/log2.rb +14 -0
  55. data/lib/more/facets/math/max.rb +1 -0
  56. data/lib/more/facets/math/mean.rb +16 -0
  57. data/lib/more/facets/math/median.rb +15 -0
  58. data/lib/more/facets/math/min.rb +35 -0
  59. data/lib/more/facets/math/pow.rb +8 -0
  60. data/lib/more/facets/math/pstd.rb +1 -0
  61. data/lib/more/facets/math/pvariance.rb +1 -0
  62. data/lib/more/facets/math/rmd.rb +16 -0
  63. data/lib/more/facets/math/root.rb +8 -0
  64. data/lib/more/facets/math/sec.rb +8 -0
  65. data/lib/more/facets/math/sech.rb +8 -0
  66. data/lib/more/facets/math/sign.rb +9 -0
  67. data/lib/more/facets/math/sinc.rb +8 -0
  68. data/lib/more/facets/math/sqr.rb +8 -0
  69. data/lib/more/facets/math/sqsolve.rb +53 -0
  70. data/lib/more/facets/math/std.rb +27 -0
  71. data/lib/more/facets/math/stderr.rb +1 -0
  72. data/lib/more/facets/math/sum.rb +16 -0
  73. data/lib/more/facets/math/summed_sqdevs.rb +14 -0
  74. data/lib/more/facets/math/theil_index.rb +24 -0
  75. data/lib/more/facets/math/variance.rb +31 -0
  76. data/lib/more/facets/thread.rb +24 -0
  77. data/lib/tour/facets/array/op_pow.rb +5 -0
  78. data/lib/tour/facets/module/enclosure.rb +15 -1
  79. data/lib/tour/facets/module/preextend.rb +26 -0
  80. data/lib/tour/facets/module/prepend.rb +39 -13
  81. data/meta/gemfile +1 -1
  82. data/qed/core/binding/caller.rdoc +1 -3
  83. data/test/core/array/test_after.rb +1 -1
  84. data/test/core/array/test_before.rb +1 -1
  85. data/test/core/array/test_conjoin.rb +1 -1
  86. data/test/core/array/test_store.rb +1 -1
  87. data/test/core/hash/test_argumentize.rb +1 -1
  88. data/test/core/hash/test_join.rb +1 -1
  89. data/test/core/kernel/test_dup.rb +1 -1
  90. data/test/core/kernel/test_get.rb +1 -1
  91. data/test/core/kernel/test_qua_class.rb +1 -1
  92. data/test/core/time/test_ago.rb +5 -117
  93. data/test/core/time/test_hence.rb +2 -2
  94. data/test/core/time/test_in.rb +4 -115
  95. data/test/core/time/test_less.rb +137 -0
  96. data/test/core/time/test_set.rb +1 -1
  97. data/test/core/time/test_shift.rb +126 -0
  98. data/test/more/test_date.rb +1 -1
  99. data/test/tour/module/test_cattr.rb +1 -1
  100. data/test/tour/module/test_class_extend.rb +1 -1
  101. data/test/tour/module/test_instance_function.rb +1 -1
  102. data/test/tour/module/test_method_space.rb +1 -1
  103. metadata +76 -10
  104. data/lib/core/facets/hash/zipnew.rb +0 -18
  105. data/lib/core/facets/kernel/clone.rb +0 -1
  106. data/lib/core/facets/kernel/dup.rb +0 -34
  107. data/lib/core/facets/kernel/replace.rb +0 -1
@@ -0,0 +1,43 @@
1
+ class Object
2
+
3
+ # Replace state of object with the state of another object of the
4
+ # same class (or superclass).
5
+ #
6
+ # class ReplaceExample
7
+ # attr_reader :a, :b
8
+ # def initialize(a,b)
9
+ # @a, @b = a, b
10
+ # end
11
+ # end
12
+ #
13
+ # obj1 = ReplaceExample.new(1,2)
14
+ # obj1.a #=> 1
15
+ # obj1.b #=> 2
16
+ #
17
+ # obj2 = ReplaceExample.new(3,4)
18
+ # obj2.a #=> 3
19
+ # obj2.b #=> 4
20
+ #
21
+ # obj1.replace(obj2)
22
+ # obj1.a #=> 3
23
+ # obj1.b #=> 4
24
+ #
25
+ # This is very similar to <code>instance.update</code>, but it is limited
26
+ # by the class of objects, in the same manner as Array#replace.
27
+ def replace(source)
28
+ raise ArgumentError, "not a #{self.class}" unless source.is_a?(self.class)
29
+ instance_variables.each do |iv|
30
+ instance_variable_set(iv, source.instance_variable_get(iv))
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+ class Struct
37
+
38
+ # Struct#replace can take a hash.
39
+ def replace(source)
40
+ source.each_pair{ |k,v| send(k.to_s + "=", v) }
41
+ end
42
+
43
+ end
@@ -0,0 +1 @@
1
+ require 'facets/object/dup'
@@ -6,6 +6,8 @@ class String
6
6
  # line of the string, stripped of whitespace on
7
7
  # either side.
8
8
  #
9
+ # "this\nthat\nother\n".cleanlines.to_a #=> ['this', 'that', 'other']
10
+ #
9
11
  def cleanlines(&block)
10
12
  if block
11
13
  scan(/^.*?$/) do |line|
@@ -1 +1 @@
1
- require 'facets/time/in'
1
+ require 'facets/time/shift'
@@ -1,93 +1 @@
1
- require 'facets/time/set'
2
- require 'facets/time/dst_adjustment'
3
-
4
- class Time
5
-
6
- # Returns a new Time representing the time a number of
7
- # time-units in the futue.
8
- #
9
- # t = Time.utc(2010,10,10,0,0,0)
10
- #
11
- # t.in(4, :days) #=> Time.utc(2010,10,14,0,0,0)
12
- #
13
- # More than one unit of time can be given.
14
- #
15
- # t.in(4, :days, 3, :hours) #=> Time.utc(2010,10,14,3,0,0)
16
- #
17
- # The #in method can also take a hash.
18
- #
19
- # t.in(:days=>4, :hours=>3) #=> Time.utc(2010,10,14,3,0,0)
20
- #
21
- def in(*time_units)
22
- time_hash = Hash===time_units.last ? time_units.pop : {}
23
- time_units << :seconds if time_units.size % 2 == 1
24
- time_hash.each{ |units, number| time_units << [number, units] }
25
- time = self
26
- time_units.flatten.each_slice(2) do |number, units|
27
- next time = time.ago(-number, units) if number < 0
28
- time = (
29
- case units.to_s.downcase.to_sym
30
- when :years, :year
31
- time.set( :year=>(year + number) )
32
- when :months, :month
33
- new_month = ((month + number - 1) % 12) + 1
34
- y = (number / 12) + (new_month < month ? 1 : 0)
35
- time.set(:year => (year + y), :month => new_month)
36
- when :weeks, :week
37
- time + (number * 604800)
38
- when :days, :day
39
- time + (number * 86400)
40
- when :hours, :hour
41
- time + (number * 3600)
42
- when :minutes, :minute, :mins, :min
43
- time + (number * 60)
44
- when :seconds, :second, :secs, :sec, nil
45
- time + number
46
- else
47
- raise ArgumentError, "unrecognized time units -- #{units}"
48
- end
49
- )
50
- end
51
- dst_adjustment(time)
52
- end
53
-
54
- # Returns a new Time representing the time
55
- # a number of time-units ago.
56
- #
57
- def ago(*time_units)
58
- time_hash = Hash===time_units.last ? time_units.pop : {}
59
- time_units << :seconds if time_units.size % 2 == 1
60
- time_hash.each{ |units, number| time_units << [number, units] }
61
- time = self
62
- time_units.each_slice(2) do |number, units|
63
- next time = time.in(-number, units) if number < 0
64
- time = (
65
- case units.to_s.downcase.to_sym
66
- when :years, :year
67
- time.set(:year => (year - number))
68
- when :months, :month
69
- new_month = ((month - number - 1) % 12) + 1
70
- y = (number / 12) + (new_month > month ? 1 : 0)
71
- time.set(:year => (year - y), :month => new_month)
72
- when :weeks, :week
73
- time - (number * 604800)
74
- when :days, :day
75
- time - (number * 86400)
76
- when :hours, :hour
77
- time - (number * 3600)
78
- when :minutes, :minute, :mins, :min
79
- time - (number * 60)
80
- when :seconds, :second, :secs, :sec, nil
81
- time - number
82
- else
83
- raise ArgumentError, "unrecognized time units -- #{units}"
84
- end
85
- )
86
- end
87
- dst_adjustment(time)
88
- end unless method_defined?(:ago)
89
-
90
- # Alias for #in.
91
- alias_method :hence, :in unless method_defined?(:hence)
92
-
93
- end
1
+ require 'facets/time/shift'
@@ -0,0 +1 @@
1
+ require 'facets/time/shift'
@@ -0,0 +1,95 @@
1
+ require 'facets/time/set'
2
+ require 'facets/time/dst_adjustment'
3
+
4
+ class Time
5
+
6
+ # Returns a new Time representing the time shifted by the time-units given.
7
+ # Positive number shift the time forward, negative number shift the time
8
+ # backward.
9
+ #
10
+ # t = Time.utc(2010,10,10,0,0,0)
11
+ # t.shift( 4, :days) #=> Time.utc(2010,10,14,0,0,0)
12
+ # t.shift(-4, :days) #=> Time.utc(2010,10,6,0,0,0)
13
+ #
14
+ # More than one unit of time can be given.
15
+ #
16
+ # t.shift(4, :days, 3, :hours) #=> Time.utc(2010,10,14,3,0,0)
17
+ #
18
+ # The #shift method can also take a hash.
19
+ #
20
+ # t.shift(:days=>4, :hours=>3) #=> Time.utc(2010,10,14,3,0,0)
21
+ #
22
+ def shift(*time_units)
23
+ time_hash = Hash===time_units.last ? time_units.pop : {}
24
+ time_units = time_units.flatten
25
+ time_units << :seconds if time_units.size % 2 == 1
26
+ time_hash.each{ |units, number| time_units << number; time_units << units }
27
+
28
+ time = self
29
+ time_units.each_slice(2) do |number, units|
30
+ #next time = time.ago(-number, units) if number < 0
31
+ time = (
32
+ case units.to_s.downcase.to_sym
33
+ when :years, :year
34
+ time.set( :year=>(year + number) )
35
+ when :months, :month
36
+ if number > 0
37
+ new_month = ((month + number - 1) % 12) + 1
38
+ y = (number / 12) + (new_month < month ? 1 : 0)
39
+ time.set(:year => (year + y), :month => new_month)
40
+ else
41
+ number = -number
42
+ new_month = ((month - number - 1) % 12) + 1
43
+ y = (number / 12) + (new_month > month ? 1 : 0)
44
+ time.set(:year => (year - y), :month => new_month)
45
+ end
46
+ when :weeks, :week
47
+ time + (number * 604800)
48
+ when :days, :day
49
+ time + (number * 86400)
50
+ when :hours, :hour
51
+ time + (number * 3600)
52
+ when :minutes, :minute, :mins, :min
53
+ time + (number * 60)
54
+ when :seconds, :second, :secs, :sec, nil
55
+ time + number
56
+ else
57
+ raise ArgumentError, "unrecognized time units -- #{units}"
58
+ end
59
+ )
60
+ end
61
+ dst_adjustment(time)
62
+ end
63
+
64
+ # Alias for #shift.
65
+ alias_method :in, :shift
66
+
67
+ # Alias for #shift.
68
+ alias_method :hence, :shift unless method_defined?(:hence)
69
+
70
+ # Returns a new Time representing the time a number of time-units ago.
71
+ # This is just like #shift, but reverses the direction.
72
+ #
73
+ # t = Time.utc(2010,10,10,0,0,0)
74
+ #
75
+ # t.less(4, :days) #=> Time.utc(2010,10,6,0,0,0)
76
+ #
77
+ def less(*time_units)
78
+ time_hash = Hash===time_units.last ? time_units.pop : {}
79
+ time_units = time_units.flatten
80
+
81
+ time_units << :seconds if time_units.size % 2 == 1
82
+
83
+ time_hash.each{ |units, number| time_units << number; time_units << units }
84
+
85
+ neg_times = []
86
+ time_units.each_slice(2){ |number, units| neg_times << -number; neg_times << units }
87
+
88
+ shift(*neg_times)
89
+ end
90
+
91
+ # Alias for #less
92
+ alias_method :ago, :less unless method_defined?(:ago)
93
+
94
+ end
95
+
@@ -0,0 +1,284 @@
1
+ # = Interval
2
+ #
3
+ # While Ruby support the Range class out of the box, is does not quite
4
+ # fullfil the role od a real Interval class. For instance, it does
5
+ # not support excluding the front sentinel. This is because Range
6
+ # also tries to do triple duty as a simple Sequence and as a simple Tuple-Pair,
7
+ # thus limiting its potential as an Interval. The Interval class remedies
8
+ # the situation by commiting to interval behavior, and then extends the class'
9
+ # capabilites beyond that of the standard Range in ways that naturally
10
+ # fall out of that.
11
+ #
12
+ # Range depends on two methods: #succ and #<=>. If numeric
13
+ # ranges were the only concern, those could just as well be #+ and #<=>,
14
+ # but esoteric forms make that unfeasible --the obvious example being a String
15
+ # range. But a proper Interval class requires mathematical continuation,
16
+ # thus the Interval depends on #+ and #<=>, as well as #- as the inverse of #+.
17
+ #
18
+ # i = Interval.new(1,5)
19
+ # i.to_a #=> [1,2,3,4,5]
20
+ #
21
+ # i = Interval[0,5]
22
+ # i.to_a(2) #=> [0,2,4]
23
+ #
24
+ # i = Interval[1,5]
25
+ # i.to_a(-1) #=> [5,4,3,2,1]
26
+ #
27
+ # i = Interval[1,3]
28
+ # i.to_a(1,2) #=> [1.0,1.5,2.0,2.5,3.0]
29
+ #
30
+ # == Authors
31
+ #
32
+ # * Thomas Sawyer
33
+ #
34
+ # == Todo
35
+ #
36
+ # * Still need to tie in Infinity.
37
+ #
38
+ # == Copying
39
+ #
40
+ # Copyright (c) 2004 Thomas Sawyer
41
+ #
42
+ # Ruby License
43
+ #
44
+ # This module is free software. You may use, modify, and/or redistribute this
45
+ # software under the same terms as Ruby.
46
+ #
47
+ # This program is distributed in the hope that it will be useful, but WITHOUT
48
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
49
+ # FOR A PARTICULAR PURPOSE.
50
+
51
+ require 'facets/multiton'
52
+ require 'facets/enumargs'
53
+ #require 'facets/infinity'
54
+
55
+ # = Interval
56
+ #
57
+ # While Ruby support the Range class out of the box, is does not quite
58
+ # fullfil the role od a real Interval class. For instance, it does
59
+ # not support excluding the front sentinel. This is because Range
60
+ # also tries to do triple duty as a simple Sequence and as a simple Tuple-Pair,
61
+ # thus limiting its potential as an Interval. The Interval class remedies
62
+ # the situation by commiting to interval behavior, and then extends the class'
63
+ # capabilites beyond that of the standard Range in ways that naturally
64
+ # fall out of that.
65
+ #
66
+ # Range depends on two methods: #succ and #<=>. If numeric
67
+ # ranges were the only concern, those could just as well be #+ and #<=>,
68
+ # but esoteric forms make that unfeasible --the obvious example being a String
69
+ # range. But a proper Interval class requires mathematical continuation,
70
+ # thus the Interval depends on #+ and #<=>, as well as #- as the inverse of #+.
71
+ #
72
+ # i = Interval.new(1,5)
73
+ # i.to_a #=> [1,2,3,4,5]
74
+ #
75
+ # i = Interval[0,5]
76
+ # i.to_a(2) #=> [0,2,4]
77
+ #
78
+ # i = Interval[1,5]
79
+ # i.to_a(-1) #=> [5,4,3,2,1]
80
+ #
81
+ # i = Interval[1,3]
82
+ # i.to_a(1,2) #=> [1.0,1.5,2.0,2.5,3.0]
83
+ #
84
+ class Interval
85
+
86
+ include Multiton
87
+ include Enumerable::Arguments
88
+
89
+ #
90
+ def self.[]( *args )
91
+ self.new( *args )
92
+ end
93
+
94
+ #
95
+ def initialize(first, last, exclude_first=false, exclude_last=false )
96
+ raise ArgumentError, "bad value for interval" if first.class != last.class
97
+ @first = first
98
+ @last = last
99
+ @exclude_first = exclude_first
100
+ @exclude_last = exclude_last
101
+ @direction = (@last <=> @first)
102
+ end
103
+
104
+ # Returns a two element array of first and last sentinels.
105
+ #
106
+ # (0..10).sentinels #=> [0,10]
107
+ #
108
+ def sentinels
109
+ return [@first, @last]
110
+ end
111
+
112
+ # Returns the first or last sentinal of the interval.
113
+ def first ; @first ; end
114
+ def last ; @last ; end
115
+
116
+ #
117
+ def exclude_first? ; @exclude_first ; end
118
+ def exclude_last? ; @exclude_last ; end
119
+
120
+ # (IMHO) these should be deprectated
121
+ alias_method( :begin, :first )
122
+ alias_method( :end, :last )
123
+ alias_method( :exclude_begin?, :exclude_first? )
124
+ alias_method( :exclude_end?, :exclude_last? )
125
+
126
+ # Returns +true+ if the start and end sentinels are equal and the interval is closed; otherwise +false+.
127
+ def degenerate? ; @direction == 0 and ! (@exclusive_first or @exclusive_last) ; end
128
+
129
+ # Returns +true+ if the start and end sentinels are equal and the interval is open; otherwise +false+.
130
+ def null? ; @direction == 0 and @exclusive_first and @exclusive_last ; end
131
+
132
+ # Returns the direction of the interval indicated by +1, 0 or -1.
133
+ #
134
+ # (1..5).direction #=> 1
135
+ # (5..1).direction #=> -1
136
+ # (1..1).direction #=> 0
137
+ #
138
+ def direction ; @direction ; end
139
+
140
+ # Returns a new interval inclusive of of both sentinels.
141
+ def closed; Interval.new(@first, @last, true, true) ; end
142
+
143
+ # Returns a new interval exclusive of both sentinels.
144
+ def opened; Interval.new(@first, @last, true, true) ; end
145
+
146
+ # Returns a new interval with either the first or the last sentinel exclusive.
147
+ # If the parameter is false, the deafult, then the first sentinel is excluded;
148
+ # if the parameter is true, the last sentinel is excluded.
149
+ def half_closed(e=false)
150
+ e ? Interval.new(@first, @last, true, false) : Interval.new(@first, @last, false, true)
151
+ end
152
+
153
+ # Returns a new interval with one of the two sentinels opened or closed
154
+ def first_closed ; Interval.new(@first, @last, false, true) ; end
155
+ def last_closed ; Interval.new(@first, @last, true, false) ; end
156
+ def first_opened ; Interval.new(@first, @last, true, false) ; end
157
+ def last_opened ; Interval.new(@first, @last, false, true) ; end
158
+
159
+ # Unary shorthands. These return a new interval exclusive of first,
160
+ # last or both sentinels, repectively.
161
+ def +@ ; Interval.new(first, last, true, false) ; end
162
+ def -@ ; Interval.new(first, last, false, true) ; end
163
+ def ~@ ; Interval.new(first, last, true, true) ; end
164
+
165
+ # Returns a new interval with the sentinels reversed.
166
+ #
167
+ # (0..10).reversed #=> 10..0
168
+ #
169
+ def reversed
170
+ Interval.new(@last, @first, true, true)
171
+ end
172
+
173
+ # Returns the length of the interval as the difference between
174
+ # the first and last elements. Returns +nil+ if the sentinal objects
175
+ # do not support distance comparison (#distance).
176
+ # TODO: Add +n+ parameter to count segmentations like those produced by #each.
177
+ def distance
178
+ @last - @first
179
+ #if @last.respond_to?( :distance )
180
+ # @last.distance( @first )
181
+ #else
182
+ # #self.to_a.length
183
+ #end
184
+ end
185
+ alias_method( :length, :distance )
186
+ alias_method( :size, :distance )
187
+
188
+ # Returns the lesser of the first and last sentinals.
189
+ def min
190
+ ((@first <=> @last) == -1) ? @first : @last
191
+ end
192
+
193
+ # Returns the greater of the first and last sentinals.
194
+ def max
195
+ ((@first <=> @last) == 1) ? @first : @last
196
+ end
197
+
198
+ # Returns true or false if the element is part of the interval.
199
+ def include?(x)
200
+ # todo: infinity?
201
+ tf = exclude_first? ? 1 : 0
202
+ tl = exclude_last? ? -1 : 0
203
+ (x <=> first) >= tf and (x <=> last) <= tl
204
+ end
205
+ alias_method( :===, :include? )
206
+ alias_method( :member?, :include? )
207
+
208
+ =begin
209
+ # def include?(x)
210
+ # tf = exclude_first? ? 1 : 0
211
+ # tl = exclude_last? ? -1 : 0
212
+ # # if other classes handled Infinity in their <=> method
213
+ # # (which probably they should) this clause would not be required
214
+ # if first.kind_of?(InfinityClass)
215
+ # ft = ((first <=> x) <= tf)
216
+ # else
217
+ # ft = (x <=> first) >= tf
218
+ # end
219
+ # if last.kind_of?(InfinityClass)
220
+ # fl = ((last <=> x) >= tl)
221
+ # else
222
+ # fl = (x <=> last) <= tl
223
+ # end
224
+ # ft && fl
225
+ # end
226
+ =end
227
+
228
+ # Iterates over the interval, passing each _n_th element to the block.
229
+ # If n is not given then n defaults to 1. Each _n_th step is determined
230
+ # by invoking +\++ or +\-+ n, depending on the direction of the interval.
231
+ # If n is negative the iteration is preformed in reverse form end sentinal
232
+ # to front sentinal. A second parameter, d, can be given in which case
233
+ # the applied step is calculated as a fraction of the interval's length
234
+ # times n / d. This allows iteration over the whole interval in equal sized
235
+ # segments.
236
+ #
237
+ # 1..5.each { |e| ... } #=> 1 2 3 4 5
238
+ # 1..5.each(2) { |e| ... } #=> 1 3 5
239
+ # 1..5.each(1,2) { |e| ... } #=> 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0
240
+ #
241
+ def each(n=1, d=nil) # :yield:
242
+ return (n < 0 ? @last : @first) if degenerate? # is this right for all values of n ?
243
+ s = d ? self.length.to_f * (n.to_f / d.to_f) : n.abs
244
+ raise "Cannot iterate over zero length steps." if s == 0
245
+ s = s * @direction
246
+ if n < 0
247
+ e = @exclude_last ? @last - s : @last
248
+ #e = @exclude_last ? @last.pred(s) : @last
249
+ t = @exclude_last ? 1 : 0
250
+ #while e.cmp(@first) >= t
251
+ while (e <=> @first) >= t
252
+ yield(e)
253
+ e -= s
254
+ #e = e.pred(s)
255
+ end
256
+ else
257
+ e = @exclude_first ? @first + s : @first
258
+ #e = @exclude_first ? @first.succ(s) : @first
259
+ t = @exclude_last ? -1 : 0
260
+ #while e.cmp(@last) <= t
261
+ while (e <=> @last) <= t
262
+ yield(e)
263
+ e += s
264
+ #e = e.succ(s)
265
+ end
266
+ end
267
+ end
268
+ alias_method( :step, :each )
269
+
270
+ # Should there be a #reverse_each ?
271
+ # Since #each can now take a negative argument, this isn't really needed.
272
+ # Should it exist anyway and routed to #each?
273
+ # Also, alias_method( :reverse_step, :reverse_each )
274
+
275
+ # Compares two intervals to see if they are equal
276
+ def eql?(other)
277
+ return false unless @first == other.first
278
+ return false unless @last == other.last
279
+ return false unless @exclude_first == other.exclude_first?
280
+ return false unless @exclude_last == other.exclude_last?
281
+ true
282
+ end
283
+
284
+ end