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

Sign up to get free protection for your applications and to get access to all the features.
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