backports 1.8.4 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,14 @@
1
1
  = Packable --- History
2
2
 
3
+ == Version 1.9.0 - September 4th, 2009
4
+
5
+ * In Ruby 1.9, most class methods of File accept filenames as String, or convertible via #to_str or #to_path.
6
+ File#to_path is also an alias to File#path. These have been backported.
7
+
8
+ * File.binread (actually IO.binread)
9
+
10
+ * BasicObject available via "require 'backports/basic_object"
11
+
3
12
  == Version 1.8.4 - September 3rd, 2009
4
13
 
5
14
  Added Dir.mktmpdir for older version of 1.8.6
@@ -68,6 +68,11 @@ Additionally, the following Ruby 1.9 have been backported:
68
68
  * Enumerator
69
69
  * +new+ (with block)
70
70
 
71
+ * File
72
+ * +binread+
73
+ * +to_path+
74
+ * All class methods accepting filenames will accept files or anything with a #to_path method.
75
+
71
76
  * Hash
72
77
  * +try_convert+
73
78
  * <tt>default_proc=</tt>
@@ -90,6 +95,10 @@ Additionally, the following Ruby 1.9 have been backported:
90
95
 
91
96
  +Enumerator+ can be accessed directly (instead of <tt>Enumerable::Enumerator</tt>)
92
97
 
98
+ Moreover, a pretty good imitation of BasicObject is available, but it must be required explicitely:
99
+
100
+ require 'backports/basic_object'
101
+
93
102
  == Rails
94
103
 
95
104
  Some generic methods from Rails methods have been copied:
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 1
3
- :minor: 8
4
- :patch: 4
3
+ :minor: 9
4
+ :patch: 0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{backports}
8
- s.version = "1.8.4"
8
+ s.version = "1.9.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Marc-Andr\303\251 Lafortune"]
12
- s.date = %q{2009-09-03}
12
+ s.date = %q{2009-09-05}
13
13
  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.
14
14
  }
15
15
  s.email = %q{github@marc-andre.ca}
@@ -57,11 +57,14 @@ Gem::Specification.new do |s|
57
57
  "lib/backports/1.9/array.rb",
58
58
  "lib/backports/1.9/enumerable.rb",
59
59
  "lib/backports/1.9/enumerator.rb",
60
+ "lib/backports/1.9/file.rb",
60
61
  "lib/backports/1.9/hash.rb",
61
62
  "lib/backports/1.9/integer.rb",
63
+ "lib/backports/1.9/io.rb",
62
64
  "lib/backports/1.9/kernel.rb",
63
65
  "lib/backports/1.9/string.rb",
64
66
  "lib/backports/1.9/symbol.rb",
67
+ "lib/backports/basic_object.rb",
65
68
  "lib/backports/rails.rb",
66
69
  "lib/backports/rails/array.rb",
67
70
  "lib/backports/rails/enumerable.rb",
@@ -71,6 +74,7 @@ Gem::Specification.new do |s|
71
74
  "lib/backports/rails/string.rb",
72
75
  "lib/backports/tools.rb",
73
76
  "test/array_test.rb",
77
+ "test/basic_object_test.rb",
74
78
  "test/binding_test.rb",
75
79
  "test/enumerable_test.rb",
76
80
  "test/enumerator_test.rb",
@@ -92,6 +96,7 @@ Gem::Specification.new do |s|
92
96
  s.summary = %q{Backports or ruby 1.8.7+ & rails for older ruby.}
93
97
  s.test_files = [
94
98
  "test/array_test.rb",
99
+ "test/basic_object_test.rb",
95
100
  "test/binding_test.rb",
96
101
  "test/enumerable_test.rb",
97
102
  "test/enumerator_test.rb",
@@ -7,24 +7,26 @@ class String
7
7
  chars.first
8
8
  end unless method_defined? :chr
9
9
 
10
- Backports.make_block_optional self, :each_byte, :each, :each_line, :test_on => "abc"
11
-
10
+ Backports.make_block_optional self, :each_byte, :each_line, :test_on => "abc"
11
+
12
+ Backports.make_block_optional self, :each, :test_on => "abc" if "is there still an each?".respond_to? :each
13
+
12
14
  # gsub: Left alone because of $~, $1, etc... which needs to be "pushed" up one level
13
15
  # It's possible to do so, but gsub is used everywhere so i felt
14
16
  # the performance hit was too big compared to the dubious gain.
15
-
17
+
16
18
  # Standard in Ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/String.html]
17
19
  unless method_defined? :each_char
18
20
  def each_char(&block)
19
21
  return to_enum(:each_char) unless block_given?
20
22
  scan(/./, &block)
21
- end
23
+ end
22
24
 
23
25
  alias_method :chars, :each_char unless method_defined? :chars
24
26
  end
25
-
27
+
26
28
  alias_method :lines, :each_line unless method_defined? :lines
27
-
29
+
28
30
  # Standard in Ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/String.html]
29
31
  def end_with?(*suffixes)
30
32
  suffixes.each do |suffix|
@@ -34,12 +36,12 @@ class String
34
36
  end
35
37
  false
36
38
  end unless method_defined? :end_with?
37
-
39
+
38
40
  # Standard in Ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/String.html]
39
41
  unless ("check partition".partition(" ") rescue false)
40
42
  def partition_with_new_meaning(pattern = Backports::Undefined, &block)
41
43
  return partition_without_new_meaning(&block) if pattern == Backports::Undefined
42
- pattern = Backports.coerce_to(pattern, String, :to_str) unless pattern.is_a? Regexp
44
+ pattern = Backports.coerce_to(pattern, String, :to_str) unless pattern.is_a? Regexp
43
45
  i = index(pattern)
44
46
  return [self, "", ""] unless i
45
47
  if pattern.is_a? Regexp
@@ -58,7 +60,7 @@ class String
58
60
  pattern = Backports.coerce_to(pattern, String, :to_str) unless pattern.is_a? Regexp
59
61
  i = rindex(pattern)
60
62
  return ["", "", self] unless i
61
-
63
+
62
64
  if pattern.is_a? Regexp
63
65
  match = Regexp.last_match
64
66
  [match.pre_match, match[0], match.post_match]
@@ -67,7 +69,7 @@ class String
67
69
  [self[0...i], self[i...last], self[last...length]]
68
70
  end
69
71
  end unless method_defined? :rpartition
70
-
72
+
71
73
  # Standard in Ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/String.html]
72
74
  def start_with?(*prefixes)
73
75
  prefixes.each do |prefix|
@@ -77,7 +79,7 @@ class String
77
79
  end
78
80
  false
79
81
  end unless method_defined? :start_with?
80
-
82
+
81
83
  # Standard in Ruby 1.8.7+. See official documentation[http://ruby-doc.org/core-1.9/classes/String.html]
82
84
  unless ("abc".upto("def", true) rescue false)
83
85
  def upto_with_exclusive(to, excl=false, &block)
@@ -1,5 +1,5 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + "/tools")
2
2
  Backports.require_relative "1.8.7"
3
- %w(array enumerable enumerator hash integer kernel string symbol).each do |lib|
3
+ %w(array enumerable enumerator hash file integer io kernel string symbol).each do |lib|
4
4
  Backports.require_relative "1.9/#{lib}"
5
5
  end
@@ -0,0 +1,23 @@
1
+ class File
2
+ def size
3
+ stat.size
4
+ end unless method_defined? :size
5
+
6
+ alias_method :to_path, :path unless method_defined? :to_path
7
+
8
+ class << self
9
+ if RUBY_VERSION < '1.9' # can't see any other reasonable way to test than this
10
+ Backports.convert_all_arguments_to_path self, 0, :delete, :unlink, :join
11
+ Backports.convert_all_arguments_to_path self, 1, :chmod, :lchmod
12
+ Backports.convert_all_arguments_to_path self, 2, :chown, :lchown
13
+
14
+ Backports.convert_first_argument_to_path self, :atime, :basename,
15
+ :blockdev?, :chardev?, :ctime, :directory?, :dirname, :executable?, :executable_real?,
16
+ :exist?, :exists?, :expand_path, :extname, :file?, :ftype, :grpowned?,
17
+ :link, :lstat, :mtime, :new, :open, :owned?, :pipe?, :readable?, :readable_real?,
18
+ :readlink, :rename, :setgid?, :setuid?, :size, :size?, :socket?,
19
+ :split, :stat, :sticky?, :symlink, :symlink?, :truncate, :writable?,
20
+ :writable_real?, :zero?
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,10 @@
1
+ class IO
2
+ class << self
3
+ def binread(file, *arg)
4
+ raise ArgumentError, "wrong number of arguments (#{1+arg.size} for 1..3)" unless arg.size < 3
5
+ File.open(Backports.convert_to_path(file),"rb") do |f|
6
+ f.read(*arg)
7
+ end
8
+ end unless method_defined? :binread
9
+ end
10
+ end
@@ -0,0 +1,52 @@
1
+ # Note: Must be required explicitely!
2
+ # This is a best attempt to fake BasicObject in Ruby 1.8.x
3
+ # What you do get:
4
+ # * as few methods as the real BasicObject (at the moment the library is required...)
5
+ # * BasicObject === <anything> # ==> returns true
6
+ # What you don't get:
7
+ # * BasicObject is not in the ancestor list of all classes and thus
8
+ # * Comparisons between classes won't work, e.g.
9
+ # Object < BasicObject # ==> returns true instead of false
10
+ # * Instance methods added to Object or Kernel after you require 'backports/basic_object'
11
+ # might also be available in instances of BasicObject and subclasses
12
+ # (they will only be undefined whenever a subclass of BasicObject is created)
13
+ # Because of all the fineprint, BasicObject must be required explicitely
14
+
15
+ require File.expand_path(File.dirname(__FILE__) + "/tools")
16
+ Backports.require_relative '1.8.7'
17
+
18
+ class BasicObject
19
+ KEEP = [:instance_eval, :instance_exec, :__send__,
20
+ "instance_eval", "instance_exec", "__send__"]
21
+ # undefine almost all instance methods
22
+ begin
23
+ old_verbose, $VERBOSE = $VERBOSE, nil # silence the warning for undefining __id__
24
+ (instance_methods - KEEP).each do |method|
25
+ undef_method method
26
+ end
27
+ ensure
28
+ $VERBOSE = old_verbose
29
+ end
30
+
31
+ class << self
32
+ def === (cmp)
33
+ true
34
+ end
35
+
36
+ # Let's try to keep things clean, in case methods have been added to Object
37
+ # either directly or through an included module.
38
+ # We'll do this whenever a class is derived from BasicObject
39
+ # Ideally, we'd do this by trapping Object.method_added
40
+ # and M.method_added for any module M included in Object or a submodule
41
+ # Seems really though to get right, but pull requests welcome ;-)
42
+ def inherited(sub)
43
+ BasicObject.class_eval do
44
+ (instance_methods - KEEP).each do |method|
45
+ if Object.method_defined?(method) && instance_method(method).owner == Object.instance_method(method).owner
46
+ undef_method method
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end unless Kernel.const_defined? :BasicObject
@@ -4,12 +4,12 @@ module Backports
4
4
  # Adapted from Pragmatic's "Programming Ruby" (since their version was buggy...)
5
5
  def self.require_relative(relative_feature)
6
6
  file = caller.first.split(/:\d/,2).first
7
- if /\A\((.*)\)/ =~ file # eval, etc.
8
- raise LoadError, "require_relative is called in #{$1}"
9
- end
7
+ if /\A\((.*)\)/ =~ file # eval, etc.
8
+ raise LoadError, "require_relative is called in #{$1}"
9
+ end
10
10
  require File.expand_path(relative_feature, File.dirname(file))
11
11
  end
12
-
12
+
13
13
  # Metaprogramming utility to make block optional.
14
14
  # Tests first if block is already optional when given options
15
15
  def self.make_block_optional mod,*methods
@@ -23,7 +23,7 @@ module Backports
23
23
  test_on = options[:test_on] || self.new
24
24
  next if (test_on.send(selector, *options.fetch(:arg, [])) rescue false)
25
25
  end
26
-
26
+
27
27
  arity = mod.instance_method(selector).arity
28
28
  last_arg = []
29
29
  if arity < 0
@@ -43,6 +43,55 @@ module Backports
43
43
  end
44
44
  end
45
45
 
46
+ # Metaprogramming utility to convert the first file argument to path
47
+ def self.convert_first_argument_to_path mod,*methods
48
+ methods.each do |selector|
49
+ unless mod.method_defined? selector
50
+ warn "#{mod}##{selector} is not defined, so argument can't converted to path"
51
+ next
52
+ end
53
+ arity = mod.instance_method(selector).arity
54
+ last_arg = []
55
+ if arity < 0
56
+ last_arg = ["*rest"]
57
+ arity = -1-arity
58
+ end
59
+ arg_sequence = (["file"] + (1...arity).map{|i| "arg_#{i}"} + last_arg + ["&block"]).join(", ")
60
+
61
+ alias_method_chain(mod, selector, :potential_path_argument) do |aliased_target, punctuation|
62
+ mod.module_eval <<-end_eval
63
+ def #{aliased_target}_with_potential_path_argument#{punctuation}(#{arg_sequence})
64
+ file = Backports.convert_to_path(file)
65
+ #{aliased_target}_without_potential_path_argument#{punctuation}(#{arg_sequence})
66
+ end
67
+ end_eval
68
+ end
69
+ end
70
+ end
71
+
72
+ # Metaprogramming utility to convert all file arguments to paths
73
+ def self.convert_all_arguments_to_path mod, skip, *methods
74
+ methods.each do |selector|
75
+ unless mod.method_defined? selector
76
+ warn "#{mod}##{selector} is not defined, so arguments can't converted to path"
77
+ next
78
+ end
79
+ first_args = (1..skip).map{|i| "arg_#{i}"}.join(",") + (skip > 0 ? "," : "")
80
+ alias_method_chain(mod, selector, :potential_path_arguments) do |aliased_target, punctuation|
81
+ mod.module_eval <<-end_eval
82
+ def #{aliased_target}_with_potential_path_arguments#{punctuation}(#{first_args}*files, &block)
83
+ files = files.map{|f| Backports.convert_to_path f}
84
+ #{aliased_target}_without_potential_path_arguments#{punctuation}(#{first_args}*files, &block)
85
+ end
86
+ end_eval
87
+ end
88
+ end
89
+ end
90
+
91
+ def self.convert_to_path(file_or_path)
92
+ coerce_to(file_or_path, String, :to_str) rescue coerce_to(file_or_path, String, :to_path) rescue file_or_path
93
+ end
94
+
46
95
  # Modified to avoid polluting Module if so desired
47
96
  # (from Rails)
48
97
  def self.alias_method_chain(mod, target, feature)
@@ -67,10 +116,10 @@ module Backports
67
116
  end
68
117
  end
69
118
  end
70
-
119
+
71
120
  # Helper method to coerce a value into a specific class.
72
121
  # Raises a TypeError if the coercion fails or the returned value
73
- # is not of the right class.
122
+ # is not of the right class.
74
123
  # (from Rubinius)
75
124
  def self.coerce_to(obj, cls, meth)
76
125
  return obj if obj.kind_of?(cls)
@@ -84,7 +133,7 @@ module Backports
84
133
  raise TypeError, "Coercion error: obj.#{meth} did NOT return a #{cls} (was #{ret.class})" unless ret.kind_of? cls
85
134
  ret
86
135
  end
87
-
136
+
88
137
  # Checks for a failed comparison (in which case it throws an ArgumentError)
89
138
  # Additionally, it maps any negative value to -1 and any positive value to +1
90
139
  # (from Rubinius)
@@ -98,7 +147,7 @@ module Backports
98
147
  # Used internally to make it easy to deal with optional arguments
99
148
  # (from Rubinius)
100
149
  Undefined = Object.new
101
-
150
+
102
151
  # A simple class which allows the construction of Enumerator from a block
103
152
  class Yielder
104
153
  def initialize(&block)
@@ -0,0 +1,70 @@
1
+ require 'test_helper'
2
+ require 'backports/basic_object'
3
+
4
+ class BasicObjectTest < Test::Unit::TestCase
5
+ context "BasicObject" do
6
+ should "do it's best to keep stuff undefined" do
7
+ # written in one big test because sequence matters
8
+ # and defining classes / methods can't really be undone
9
+
10
+ assert_equal 3, BasicObject.instance_methods.size
11
+
12
+ class Subclass < BasicObject
13
+ def foo
14
+ :bar
15
+ end
16
+ end
17
+
18
+ assert_equal 4, Subclass.instance_methods.size
19
+
20
+ module ::Kernel
21
+ def bar
22
+ :foo
23
+ end
24
+ end
25
+
26
+ assert Subclass.method_defined?(:bar) # for now
27
+
28
+ class ForceCleanup < Subclass
29
+ end
30
+
31
+ assert !Subclass.method_defined?(:bar) # should be cleaned up
32
+
33
+ module SomeExtension
34
+ def foo
35
+ 42
36
+ end
37
+ end
38
+
39
+ class ::Object
40
+ include SomeExtension
41
+ end
42
+
43
+ class ForceCleanupAgain < Subclass
44
+ end
45
+
46
+ # puts BasicObject.instance_methods - BasicObject.instance_methods(false)
47
+ # puts BasicObject.instance_method(:foo).owner
48
+ # puts SomeExtension <= Object
49
+ assert Subclass.method_defined?(:foo) # should not be cleaned up!
50
+ assert !BasicObject.method_defined?(:foo) # but BasicObject should have been cleaned up!
51
+
52
+ class BasicObject
53
+ def last_case
54
+ 1.0/0
55
+ end
56
+ end
57
+
58
+ module SomeExtension
59
+ def last_case
60
+ 0
61
+ end
62
+ end
63
+
64
+ class ForceCleanupForTheLastTime < BasicObject
65
+ end
66
+
67
+ assert BasicObject.method_defined?(:last_case)
68
+ end
69
+ end
70
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: backports
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.4
4
+ version: 1.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - "Marc-Andr\xC3\xA9 Lafortune"
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-09-03 00:00:00 -04:00
12
+ date: 2009-09-05 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -62,11 +62,14 @@ files:
62
62
  - lib/backports/1.9/array.rb
63
63
  - lib/backports/1.9/enumerable.rb
64
64
  - lib/backports/1.9/enumerator.rb
65
+ - lib/backports/1.9/file.rb
65
66
  - lib/backports/1.9/hash.rb
66
67
  - lib/backports/1.9/integer.rb
68
+ - lib/backports/1.9/io.rb
67
69
  - lib/backports/1.9/kernel.rb
68
70
  - lib/backports/1.9/string.rb
69
71
  - lib/backports/1.9/symbol.rb
72
+ - lib/backports/basic_object.rb
70
73
  - lib/backports/rails.rb
71
74
  - lib/backports/rails/array.rb
72
75
  - lib/backports/rails/enumerable.rb
@@ -76,6 +79,7 @@ files:
76
79
  - lib/backports/rails/string.rb
77
80
  - lib/backports/tools.rb
78
81
  - test/array_test.rb
82
+ - test/basic_object_test.rb
79
83
  - test/binding_test.rb
80
84
  - test/enumerable_test.rb
81
85
  - test/enumerator_test.rb
@@ -124,6 +128,7 @@ specification_version: 3
124
128
  summary: Backports or ruby 1.8.7+ & rails for older ruby.
125
129
  test_files:
126
130
  - test/array_test.rb
131
+ - test/basic_object_test.rb
127
132
  - test/binding_test.rb
128
133
  - test/enumerable_test.rb
129
134
  - test/enumerator_test.rb