backports 1.6.8 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ *.sw?
2
+ *.rbc
3
+ .DS_Store
4
+ coverage
5
+ rdoc
6
+ pkg
7
+ assets
data/CHANGELOG.rdoc CHANGED
@@ -1,5 +1,13 @@
1
1
  = Packable --- History
2
2
 
3
+ == Version 1.7 - May 27, 2009
4
+
5
+ Porting all 1.8.7 features to rubinius was quite enlightening (http://blog.marc-andre.ca/2009/05/schizo-ruby-puzzle.html ).
6
+ Many improvements were made to be consistent with MRI, e.g. converting arguments using to_int if needed, etc...
7
+ The changes are now reflected in 'backports'.
8
+
9
+ Some IO and ARGF methods were missing and are now complete.
10
+
3
11
  == Version 1.6.6 - April 30, 2009
4
12
 
5
13
  Important bug fix. String#gsub is left alone until I find a good way to modify it.
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 1
3
- :minor: 6
4
- :patch: 8
3
+ :minor: 7
4
+ :patch: 0
data/backports.gemspec ADDED
@@ -0,0 +1,98 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{backports}
5
+ s.version = "1.7.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Marc-Andr\303\251 Lafortune"]
9
+ s.date = %q{2009-05-31}
10
+ s.description = %q{Essential backports that enable some of the really nice features of ruby 1.8.7, ruby 1.9 and rails from ruby 1.8.6 and earlier.}
11
+ s.email = %q{github@marc-andre.ca}
12
+ s.extra_rdoc_files = [
13
+ "LICENSE",
14
+ "README.rdoc"
15
+ ]
16
+ s.files = [
17
+ ".document",
18
+ ".gitignore",
19
+ "CHANGELOG.rdoc",
20
+ "LICENSE",
21
+ "README.rdoc",
22
+ "Rakefile",
23
+ "VERSION.yml",
24
+ "backports.gemspec",
25
+ "lib/backports.rb",
26
+ "lib/backports/argf.rb",
27
+ "lib/backports/array.rb",
28
+ "lib/backports/binding.rb",
29
+ "lib/backports/core_ext.rb",
30
+ "lib/backports/dir.rb",
31
+ "lib/backports/enumerable.rb",
32
+ "lib/backports/enumerator.rb",
33
+ "lib/backports/env.rb",
34
+ "lib/backports/fixnum.rb",
35
+ "lib/backports/float.rb",
36
+ "lib/backports/gc.rb",
37
+ "lib/backports/hash.rb",
38
+ "lib/backports/integer.rb",
39
+ "lib/backports/io.rb",
40
+ "lib/backports/kernel.rb",
41
+ "lib/backports/method.rb",
42
+ "lib/backports/module.rb",
43
+ "lib/backports/numeric.rb",
44
+ "lib/backports/object_space.rb",
45
+ "lib/backports/proc.rb",
46
+ "lib/backports/process.rb",
47
+ "lib/backports/range.rb",
48
+ "lib/backports/regexp.rb",
49
+ "lib/backports/string.rb",
50
+ "lib/backports/struct.rb",
51
+ "lib/backports/symbol.rb",
52
+ "test/array_test.rb",
53
+ "test/binding_test.rb",
54
+ "test/enumerable_test.rb",
55
+ "test/enumerator_test.rb",
56
+ "test/hash_test.rb",
57
+ "test/kernel_test.rb",
58
+ "test/method_test.rb",
59
+ "test/module_test.rb",
60
+ "test/object_test.rb",
61
+ "test/regexp_test.rb",
62
+ "test/string_test.rb",
63
+ "test/symbol_test.rb",
64
+ "test/test_helper.rb"
65
+ ]
66
+ s.has_rdoc = true
67
+ s.homepage = %q{http://github.com/marcandre/backports}
68
+ s.rdoc_options = ["--charset=UTF-8", "--title", "Backports library", "--main", "README.rdoc", "--line-numbers", "--inline-source"]
69
+ s.require_paths = ["lib"]
70
+ s.rubyforge_project = %q{backports}
71
+ s.rubygems_version = %q{1.3.1}
72
+ s.summary = %q{Backports or ruby 1.8.7+ & rails for older ruby.}
73
+ s.test_files = [
74
+ "test/array_test.rb",
75
+ "test/binding_test.rb",
76
+ "test/enumerable_test.rb",
77
+ "test/enumerator_test.rb",
78
+ "test/hash_test.rb",
79
+ "test/kernel_test.rb",
80
+ "test/method_test.rb",
81
+ "test/module_test.rb",
82
+ "test/object_test.rb",
83
+ "test/regexp_test.rb",
84
+ "test/string_test.rb",
85
+ "test/symbol_test.rb",
86
+ "test/test_helper.rb"
87
+ ]
88
+
89
+ if s.respond_to? :specification_version then
90
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
91
+ s.specification_version = 2
92
+
93
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
94
+ else
95
+ end
96
+ else
97
+ end
98
+ end
data/lib/backports.rb CHANGED
@@ -10,13 +10,6 @@ module Kernel
10
10
  end unless method_defined? :require_relative
11
11
  end
12
12
 
13
- class Array
14
- # Standard in rails, and we use it in module.
15
- def extract_options!
16
- last.is_a?(::Hash) ? pop : {}
17
- end unless method_defined? :extract_options!
18
- end
19
-
20
- %w(object module kernel object_space array enumerable enumerator string symbol integer fixnum hash proc binding dir io method regexp struct).each do |lib|
13
+ %w(core_ext module kernel array enumerable enumerator string symbol integer numeric fixnum hash proc binding dir io method regexp struct float object_space argf gc env process).each do |lib|
21
14
  require_relative "backports/#{lib}"
22
15
  end
@@ -0,0 +1,57 @@
1
+ if RUBY_VERSION < '1.8.7'
2
+ class << ARGF
3
+ # Standard in Ruby 1.8.7.
4
+ make_block_optional :each, :each_line, :each_byte
5
+ end
6
+ end
7
+
8
+ class << ARGF
9
+ # Standard in Ruby 1.8.7.
10
+ def bytes
11
+ to_enum :each_byte
12
+ end unless method_defined? :bytes
13
+
14
+ # Standard in Ruby 1.8.7.
15
+ def chars
16
+ to_enum :each_char
17
+ end unless method_defined? :chars
18
+
19
+ # Standard in Ruby 1.8.7.
20
+ def each_char
21
+ return to_enum(:each_char) unless block_given?
22
+ if $KCODE == "UTF-8"
23
+ lookup = 7.downto(4)
24
+ while c = read(1) do
25
+ n = c[0]
26
+ leftmost_zero_bit = lookup.find{|i| n[i].zero? }
27
+ case leftmost_zero_bit
28
+ when 7 # ASCII
29
+ yield c
30
+ when 6 # UTF 8 complementary characters
31
+ next # Encoding error, ignore
32
+ else
33
+ more = read(6-leftmost_zero_bit)
34
+ break unless more
35
+ yield c+more
36
+ end
37
+ end
38
+ else
39
+ while s = read(1)
40
+ yield s
41
+ end
42
+ end
43
+
44
+ self
45
+ end unless method_defined? :each_char
46
+
47
+ # Standard in Ruby 1.8.7.
48
+ alias_method :getbyte, :getc
49
+
50
+ # Standard in Ruby 1.8.7.
51
+ alias_method :readbyte, :readchar
52
+
53
+ # Standard in Ruby 1.8.7.
54
+ def lines(*args)
55
+ to_enum :each_line, *args
56
+ end unless method_defined? :lines
57
+ end
@@ -1,17 +1,19 @@
1
1
  class Array
2
+ # Standard in Ruby 1.9. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
2
3
  class << self
3
- # Standard in Ruby 1.9. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
4
- def try_convert(x)
5
- x.to_ary if x.respond_to? :to_ary
6
- end unless method_defined? :try_convert
4
+ # Try to convert obj into an array, using to_ary method.
5
+ # Returns converted array or nil if obj cannot be converted
6
+ # for any reason. This method is to check if an argument is an array.
7
+ def try_convert(obj)
8
+ return nil unless obj.respond_to?(:to_ary)
9
+ Type.coerce_to(obj, Array, :to_ary)
10
+ end
7
11
  end
8
12
 
9
- # Standard in Ruby 1.9. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
10
- make_block_optional :collect!, :map!, :each, :each_index, :reverse_each, :reject, :reject!, :delete_if, :test_on => [42]
11
-
12
- # Standard in Ruby 1.9. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
13
+
14
+ # Standard in Ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
13
15
  def combination(num)
14
- num = num.to_i
16
+ num = Type.coerce_to num, Fixnum, :to_int
15
17
  return to_enum(:combination, num) unless block_given?
16
18
  return self unless (0..size).include? num
17
19
  # Implementation note: slightly tricky.
@@ -27,32 +29,43 @@ class Array
27
29
  picks[move...num] = (new_index...(new_index+num-move)).to_a
28
30
  end
29
31
  end unless method_defined? :combination
30
-
31
- # Standard in Ruby 1.9. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
32
- def cycle(*arg, &block)
33
- return to_enum(:cycle, *arg) unless block_given?
34
- nb = arg.empty? ? (1/0.0) : arg.first
35
- nb.to_i.times{each(&block)}
32
+
33
+ # Standard in Ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
34
+ def cycle(n = nil, &block)
35
+ return to_enum(:cycle, n) unless block_given?
36
+ if n.nil?
37
+ loop(&block)
38
+ else
39
+ n = Type.coerce_to n, Fixnum, :to_int
40
+ n.times{each(&block)}
41
+ end
42
+ nil
36
43
  end unless method_defined? :cycle
37
-
38
- # extract_options! in backports.rb
39
-
40
- # flatten & flatten!, standard in ruby 1.9. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
44
+
45
+ # Standard in rails, and we use it here...
46
+ def extract_options!
47
+ last.is_a?(::Hash) ? pop : {}
48
+ end unless method_defined? :extract_options!
49
+
50
+ # Standard in Ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
51
+ make_block_optional :collect!, :map!, :each, :each_index, :reverse_each, :reject, :reject!, :delete_if, :test_on => [42]
52
+
53
+ # flatten & flatten!, standard in ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
41
54
  unless ([[]].flatten(1) rescue false)
42
55
 
43
56
  # Recursively flatten any contained Arrays into an one-dimensional result.
44
57
  # Adapted from rubinius'
45
- def flatten_with_optional_argument(level=nil)
46
- return flatten_without_optional_argument unless level || level == (1/0.0)
58
+ def flatten_with_optional_argument(level=-1)
47
59
  dup.flatten!(level) || self
48
60
  end
49
61
 
50
62
  # Flattens self in place as #flatten. If no changes are
51
63
  # made, returns nil, otherwise self.
52
64
  # Adapted from rubinius'
53
- def flatten_with_optional_argument!(level=nil)
54
- return flatten_without_optional_argument! unless level || level == (1/0.0)
55
-
65
+ def flatten_with_optional_argument!(level=-1)
66
+ level = Type.coerce_to(level, Integer, :to_int)
67
+ return flatten_without_optional_argument! unless level >= 0
68
+
56
69
  ret, out = nil, []
57
70
  ret = recursively_flatten_finite(self, out, level)
58
71
  replace(out) if ret
@@ -82,8 +95,8 @@ class Array
82
95
  end
83
96
  private :recursively_flatten_finite
84
97
  end # flatten & flatten!
85
-
86
- # index
98
+
99
+ # index. Standard in Ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
87
100
  unless ([1].index{true} rescue false)
88
101
  def index_with_block(*arg)
89
102
  return index_without_block(*arg) unless block_given? && arg.empty?
@@ -93,27 +106,37 @@ class Array
93
106
  alias_method_chain :index, :block
94
107
  alias_method :find_index, :index
95
108
  end
96
-
97
- # pop. Standard in Ruby 1.9. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
109
+
110
+ # pop. Standard in Ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
98
111
  unless ([1].pop(1) rescue false)
99
- def pop_with_optional_argument(*arg)
100
- return pop_without_optional_argument if arg.empty?
101
- n = arg.first.to_i
102
- slice!([0,size-n].max, size)
112
+ def pop_with_optional_argument(n = Undefined)
113
+ return pop_without_optional_argument if n == Undefined
114
+ n = Type.coerce_to(n, Fixnum, :to_int)
115
+ raise ArgumentError, "negative array size" if n < 0
116
+ first = size - n
117
+ first = 0 if first < 0
118
+ slice!(first..size).to_a
103
119
  end
104
120
  alias_method_chain :pop, :optional_argument
105
121
  end
106
-
122
+
123
+ # Standard in Ruby 1.9. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
107
124
  def product(*arg)
125
+ # Implementation notes: We build an enumerator for all the combinations
126
+ # by building it up successively using "inject" and starting from a trivial enumerator.
127
+ # It would be easy to have "product" yield to a block but the standard
128
+ # simply returns an array, so you'll find a simple call to "to_a" at the end.
129
+ #
108
130
  trivial_enum = Enumerator.new{|yielder| yielder.yield [] }
109
- [self, *arg].inject(trivial_enum) do |enum, array|
110
- Enumerator.new do |yielder|
111
- enum.each do |partial_product|
112
- array.each do |obj|
113
- yielder.yield partial_product + [obj]
131
+ [self, *arg].map{|x| Type.coerce_to(x, Array, :to_ary)}.
132
+ inject(trivial_enum) do |enum, array|
133
+ Enumerator.new do |yielder|
134
+ enum.each do |partial_product|
135
+ array.each do |obj|
136
+ yielder.yield partial_product + [obj]
137
+ end
114
138
  end
115
139
  end
116
- end
117
140
  end.to_a
118
141
  end unless method_defined? :product
119
142
 
@@ -126,35 +149,45 @@ class Array
126
149
  end
127
150
  alias_method_chain :rindex, :block
128
151
  end
129
-
130
- # shift. Standard in Ruby 1.9. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
152
+
153
+ # Standard in Ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
154
+ def sample(n = Undefined)
155
+ return self[rand(size)] if n == Undefined
156
+ n = Type.coerce_to(n, Fixnum, :to_int)
157
+ raise ArgumentError, "negative array size" if n < 0
158
+ n = size if n > size
159
+ result = Array.new(self)
160
+ n.times do |i|
161
+ r = i + rand(size - i)
162
+ result[i], result[r] = result[r], result[i]
163
+ end
164
+ result[n..size] = []
165
+ result
166
+ end unless method_defined? :sample
167
+
168
+ # shift. Standard in Ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
131
169
  unless ([1].shift(1) rescue false)
132
- def shift_with_optional_argument(*arg)
133
- return shift_without_optional_argument if arg.empty?
134
- n = arg.first.to_i
170
+ def shift_with_optional_argument(n = Undefined)
171
+ return shift_without_optional_argument if n == Undefined
172
+ n = Type.coerce_to(n, Fixnum, :to_int)
173
+ raise ArgumentError, "negative array size" if n < 0
135
174
  slice!(0, n)
136
175
  end
137
176
  alias_method_chain :shift, :optional_argument
138
177
  end
139
-
140
-
141
- def sample(*arg)
142
- return self[rand(size)] if arg.empty?
143
- n = [arg.first.to_i, size].min
144
- index = Array.new(size)
145
- n.times do |i|
146
- r = i + rand(size - i)
147
- index[i], index[r] = index[r] || r, index[i] || i
148
- end
149
- values_at(*index.first(n))
150
- end unless method_defined? :sample
151
-
178
+
179
+ # Standard in Ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
152
180
  def shuffle
153
- sample(size)
181
+ dup.shuffle!
154
182
  end unless method_defined? :shuffle
155
183
 
184
+ # Standard in Ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/Array.html]
156
185
  def shuffle!
157
- replace(sample(size))
186
+ size.times do |i|
187
+ r = i + rand(size - i)
188
+ self[i], self[r] = self[r], self[i]
189
+ end
190
+ self
158
191
  end unless method_defined? :shuffle!
159
192
 
160
193
  end
@@ -1,5 +1,5 @@
1
1
  class Binding
2
- # Standard in ruby 1.9. See official documentation[http://ruby-doc.org/core-1.9/classes/Symbol.html]
2
+ # Standard in ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/Symbol.html]
3
3
  def eval(expr, *arg)
4
4
  Kernel.eval(expr, self, *arg)
5
5
  end unless method_defined? :eval
@@ -0,0 +1,61 @@
1
+ # These are non-standard extensions
2
+
3
+ class Module
4
+ # Metaprogramming utility to make block optional.
5
+ # Tests first if block is already optional when given options
6
+ def make_block_optional(*methods)
7
+ options = methods.extract_options!
8
+ methods.each do |selector|
9
+ next unless method_defined? selector
10
+ unless options.empty?
11
+ test_on = options[:test_on] || self.new
12
+ next if (test_on.send(selector, *options.fetch(:arg, [])) rescue false)
13
+ end
14
+
15
+ arity = instance_method(selector).arity
16
+ last_arg = []
17
+ if arity < 0
18
+ last_arg = ["*rest"]
19
+ arity = -1-arity
20
+ end
21
+ arg_sequence = ((0...arity).map{|i| "arg_#{i}"} + last_arg + ["&block"]).join(", ")
22
+
23
+ alias_method_chain(selector, :optional_block) do |aliased_target, punctuation|
24
+ module_eval <<-end_eval
25
+ def #{aliased_target}_with_optional_block#{punctuation}(#{arg_sequence})
26
+ return to_enum(:#{aliased_target}_without_optional_block#{punctuation}, #{arg_sequence}) unless block_given?
27
+ #{aliased_target}_without_optional_block#{punctuation}(#{arg_sequence})
28
+ end
29
+ end_eval
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ module Type
36
+ # From Rubinius
37
+ class << self
38
+ def coerce_to(obj, cls, meth)
39
+ return obj if obj.kind_of?(cls)
40
+
41
+ begin
42
+ ret = obj.__send__(meth)
43
+ rescue Exception => e
44
+ raise TypeError, "Coercion error: #{obj.inspect}.#{meth} => #{cls} failed:\n" \
45
+ "(#{e.message})"
46
+ end
47
+ raise TypeError, "Coercion error: obj.#{meth} did NOT return a #{cls} (was #{ret.class})" unless ret.kind_of? cls
48
+ ret
49
+ end unless method_defined? :coerce_to
50
+ end
51
+
52
+ def self.coerce_to_comparison(a, b, cmp = (a <=> b))
53
+ raise ArgumentError, "comparison of #{a} with #{b} failed" if cmp.nil?
54
+ return 1 if cmp > 0
55
+ return -1 if cmp < 0
56
+ 0
57
+ end unless method_defined? :coerce_to_comparison
58
+ end
59
+
60
+ # From Rubinius
61
+ Undefined = Object.new unless Kernel.const_defined? :Undefined