polyfill 0.7.0 → 0.8.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f89fe1c04a0c5226662965adf194eca6e5efb720
4
- data.tar.gz: 714c012252e26b39e93e3967af657a1ba1a6b7f2
3
+ metadata.gz: ce45400dde62a6c4481017080a3770fe3557619e
4
+ data.tar.gz: 29d853335b679ed69d51df345786021e8919b121
5
5
  SHA512:
6
- metadata.gz: 518365852878a1fd4146557895021ecaeff61ae04804e5d386bf43623a8f5114e3cfc7fc8801c978654f83403cff56326fa63e55795cbc3b89fc3d4653a02ddb
7
- data.tar.gz: 27082bfce68e460d5dc49697f6020194293631b5b1170653a1edf04bc8145e2d002e3027d110094ee238adf58d76aed0c7b4d29bfe7bc521c12a499453918945
6
+ metadata.gz: 2f9a80ce2cc37783a1060d403317eb5e142c6c1a97a81057fc4123c9c7d8e7fcf6fcbec1f40d130d43ef8ad737df0db2f55c09b62f2a10de674d815d88b01f2d
7
+ data.tar.gz: e465ec4b46c0ba099cfd5121402e6366eeca20991f6c00d03656127b0cfb6fe36159f5fd87d955655282e0bc076025d69a1622e10357f81996c7e3bd2ec6525b
data/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ # [0.8.0][] (2017-04-27)
2
+
3
+ ## Changed
4
+
5
+ - `Polyfill()` is no longer used with `include` or `extend`. Instead `Polyfill.get` should
6
+ be used.
7
+
8
+ ## Added
9
+
10
+ - Polyfill.get for getting modules to include or extend
11
+ - v2.2 Enumerable#slice_when
12
+
13
+ ## Fixed
14
+
15
+ - v2.3 Enumerable#chunk_while and v2.2 Enumerable#slice_after should not require `count`
16
+ - v2.4 Array#sum should not use `each` (the Enumerable version does)
17
+ - load modules before classes so they don't override the local method
18
+
1
19
  # [0.7.0][] (2017-04-22)
2
20
 
3
21
  ## Changed
@@ -123,6 +141,7 @@
123
141
  - v2.4 String#concat?
124
142
  - v2.4 String#prepend?
125
143
 
144
+ [0.8.0]: https://github.com/AaronLasseigne/polyfill/compare/v0.7.0...v0.8.0
126
145
  [0.7.0]: https://github.com/AaronLasseigne/polyfill/compare/v0.6.0...v0.7.0
127
146
  [0.6.0]: https://github.com/AaronLasseigne/polyfill/compare/v0.5.0...v0.6.0
128
147
  [0.5.0]: https://github.com/AaronLasseigne/polyfill/compare/v0.4.0...v0.5.0
data/README.md CHANGED
@@ -33,7 +33,7 @@ See the [implementation table](#implementation-table) for specifics about what h
33
33
  Add it to your Gemfile:
34
34
 
35
35
  ```ruby
36
- gem 'polyfill', '0.7.0'
36
+ gem 'polyfill', '0.8.0'
37
37
  ```
38
38
 
39
39
  Or install it manually:
@@ -52,6 +52,8 @@ This project uses [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
52
52
 
53
53
  ## Usage
54
54
 
55
+ ### Polyfill
56
+
55
57
  With the `Polyfill` method, you can polyfill methods for one or more Ruby
56
58
  objects. Each object is passed as a key. The value is an array of strings
57
59
  containing the methods you would like to polyfill. Instance methods need to
@@ -88,15 +90,37 @@ This currently adds support for `respond_to?`, `__send__`, and `send`.
88
90
  using Polyfill(native: true, Numeric: :all)
89
91
  ```
90
92
 
93
+ ### Polyfill.get
94
+
91
95
  Prior to Ruby 2.4, refinements do not work on Modules. When using a polyfill
92
96
  on a module it will instead refine the core classes that use the module. If
93
97
  you're building your own class, it will not receive the polyfill. Instead,
94
- you can add the polyfill by using `include`.
98
+ you can `include` (or `extend`) in a polyfill with `Polyfill.get`.
99
+
100
+ ```ruby
101
+ class Foo
102
+ include Comparable
103
+ include Polyfill.get(:Comparable, :all)
104
+ end
105
+ ```
106
+
107
+ To use specific methods you can pass an array of symbols in place of `:all`.
95
108
 
96
109
  ```ruby
97
110
  class Foo
98
111
  include Comparable
99
- include Polyfill(Comparable: :all)
112
+ include Polyfill.get(:Comparable, %i[clamp])
113
+ end
114
+ ```
115
+
116
+ Like before, the polyfills can be halted at a maximum version with the
117
+ `:version` option. The version must be a string with the major and minor
118
+ version only.
119
+
120
+ ```ruby
121
+ class Foo
122
+ include Comparable
123
+ include Polyfill.get(:Comparable, :all, version: '2.3')
100
124
  end
101
125
  ```
102
126
 
@@ -111,7 +135,7 @@ end
111
135
  | | #min | No | This method already existed but was inherited from `Enumerable`. It was optimized on `Array` so redefining `Enumerable#min` no longer affects this.
112
136
  | | #pack | No |
113
137
  | | #sum | Yes |
114
- | BasicObject | #__send__ | No |
138
+ | BasicObject | #\_\_send\_\_ | No |
115
139
  | Binding | #irb | No |
116
140
  | Comparable | #clamp | Yes |
117
141
  | CSV | #new | No |
@@ -297,7 +321,7 @@ end
297
321
  | | #min | No |
298
322
  | | #min_by | No |
299
323
  | | #slice_after | Yes |
300
- | | #slice_when | No |
324
+ | | #slice_when | Yes |
301
325
  | Etc | .confstr | No |
302
326
  | | .sysconf | No |
303
327
  | | .nprocessors | No |
@@ -306,9 +330,8 @@ end
306
330
  | | #prev_float | No |
307
331
  | File | .birthtime | No |
308
332
  | | #birthtime | No |
309
- | | .find | No |
310
- | | #find | No |
311
333
  | File::Stat | #birthtime | No |
334
+ | Find | .find | No |
312
335
  | GC | .latest_gc_info | No |
313
336
  | | .stat | No |
314
337
  | IO | #each_codepoint | No |
data/Rakefile CHANGED
@@ -3,6 +3,8 @@ require 'rspec/core/rake_task'
3
3
  require 'rubocop/rake_task'
4
4
 
5
5
  RSpec::Core::RakeTask.new(:spec)
6
- RuboCop::RakeTask.new
6
+ RuboCop::RakeTask.new(:rubocop) do |task|
7
+ task.options = ['--display-cop-names']
8
+ end
7
9
 
8
10
  task default: %i[spec rubocop]
data/lib/polyfill.rb CHANGED
@@ -5,6 +5,99 @@ require 'polyfill/utils'
5
5
 
6
6
  module Polyfill
7
7
  module Parcel; end
8
+
9
+ def get(module_name, methods, options = {})
10
+ if Object.const_get(module_name.to_s).is_a?(Class)
11
+ raise ArgumentError, "#{module_name} is a class not a module"
12
+ end
13
+
14
+ #
15
+ # parse options
16
+ #
17
+ versions = {
18
+ '2.2' => Polyfill::V2_2,
19
+ '2.3' => Polyfill::V2_3,
20
+ '2.4' => Polyfill::V2_4
21
+ }
22
+ desired_version = options.delete(:version) || versions.keys.max
23
+ unless versions.keys.include?(desired_version)
24
+ raise ArgumentError, "invalid value for keyword version: #{desired_version}"
25
+ end
26
+ versions.reject! do |version_number, _|
27
+ version_number > desired_version
28
+ end
29
+
30
+ unless options.empty?
31
+ raise ArgumentError, "unknown keyword: #{options.first[0]}"
32
+ end
33
+
34
+ #
35
+ # find all polyfills for the module across all versions
36
+ #
37
+ module_names = module_name.to_s.split('::')
38
+ current_ruby_version = RUBY_VERSION[/\A(\d+\.\d+)/, 1]
39
+
40
+ modules_with_updates = []
41
+ modules = []
42
+ versions.each do |version_number, version_module|
43
+ begin
44
+ final_module = module_names
45
+ .reduce(version_module) do |current_mod, name|
46
+ current_mod.const_get(name, false)
47
+ end
48
+
49
+ modules_with_updates << final_module
50
+
51
+ next if version_number <= current_ruby_version
52
+
53
+ modules << final_module.clone
54
+ rescue NameError
55
+ nil
56
+ end
57
+ end
58
+
59
+ if modules_with_updates.empty?
60
+ raise ArgumentError, %Q("#{module_name}" has no updates)
61
+ end
62
+
63
+ #
64
+ # remove methods that were not requested
65
+ #
66
+ methods_with_updates = modules_with_updates.flat_map(&:instance_methods).uniq
67
+ requested_methods = methods == :all ? methods_with_updates : methods
68
+
69
+ unless (leftovers = (requested_methods - methods_with_updates)).empty?
70
+ raise ArgumentError, %Q("##{leftovers.first}" is not a valid method on #{module_name} or has no updates)
71
+ end
72
+
73
+ modules.each do |instance_module|
74
+ instance_module.instance_methods.each do |name|
75
+ instance_module.send(:remove_method, name) unless requested_methods.include?(name)
76
+ end
77
+ end
78
+
79
+ #
80
+ # build the module to return
81
+ #
82
+ mod = Module.new
83
+
84
+ # make sure the methods get added if this module is included
85
+ mod.singleton_class.send(:define_method, :included) do |base|
86
+ modules.each do |module_to_add|
87
+ base.include module_to_add unless module_to_add.instance_methods.empty?
88
+ end
89
+ end
90
+
91
+ # make sure the methods get added if this module is extended
92
+ mod.singleton_class.send(:define_method, :extended) do |base|
93
+ modules.each do |module_to_add|
94
+ base.extend module_to_add unless module_to_add.instance_methods.empty?
95
+ end
96
+ end
97
+
98
+ Polyfill::Parcel.const_set("O#{mod.object_id}", mod)
99
+ end
100
+ module_function :get
8
101
  end
9
102
 
10
103
  def Polyfill(options = {}) # rubocop:disable Style/MethodName
@@ -14,6 +107,15 @@ def Polyfill(options = {}) # rubocop:disable Style/MethodName
14
107
  # parse options
15
108
  #
16
109
  objects, others = options.partition { |key,| key[/\A[A-Z]/] }
110
+ objects.sort! do |a, b|
111
+ if !a.is_a?(Class) && b.is_a?(Class)
112
+ -1
113
+ elsif a.is_a?(Class) && !b.is_a?(Class)
114
+ 1
115
+ else
116
+ 0
117
+ end
118
+ end
17
119
  others = others.to_h
18
120
 
19
121
  versions = {
@@ -36,10 +138,9 @@ def Polyfill(options = {}) # rubocop:disable Style/MethodName
36
138
  end
37
139
 
38
140
  #
39
- # useful vars
141
+ # useful var
40
142
  #
41
143
  current_ruby_version = RUBY_VERSION[/\A(\d+\.\d+)/, 1]
42
- all_instance_modules = []
43
144
 
44
145
  objects.each do |full_name, methods|
45
146
  #
@@ -63,7 +164,7 @@ def Polyfill(options = {}) # rubocop:disable Style/MethodName
63
164
  .compact
64
165
 
65
166
  if object_modules.empty?
66
- raise ArgumentError, %Q("#{full_name}" is not a valid class or has no updates)
167
+ raise ArgumentError, %Q("#{full_name}" is not a valid object or has no updates)
67
168
  end
68
169
 
69
170
  #
@@ -172,8 +273,6 @@ def Polyfill(options = {}) # rubocop:disable Style/MethodName
172
273
 
173
274
  next if instance_module.instance_methods.empty?
174
275
 
175
- all_instance_modules << instance_module
176
-
177
276
  mod.module_exec(requested_instance_methods) do |methods_added|
178
277
  base_classes.each do |klass|
179
278
  refine Object.const_get(klass) do
@@ -201,15 +300,6 @@ def Polyfill(options = {}) # rubocop:disable Style/MethodName
201
300
  end
202
301
  end
203
302
 
204
- #
205
- # make sure the includes get added if this module is included
206
- #
207
- mod.singleton_class.send(:define_method, :included) do |base|
208
- all_instance_modules.each do |instance_module|
209
- base.include instance_module
210
- end
211
- end
212
-
213
303
  Polyfill::Parcel.const_set("O#{mod.object_id}", mod)
214
304
  end
215
305
 
@@ -6,27 +6,38 @@ module Polyfill
6
6
  raise ArgumentError, 'wrong number of arguments (given 0, expected 1)' if !pattern && !block_given?
7
7
 
8
8
  matcher = pattern || ::Proc.new
9
- enum_count =
10
- begin
11
- size
12
- rescue NameError
13
- count
14
- end
15
9
 
16
10
  ::Enumerator.new do |yielder|
17
11
  output = []
18
- run = 1
19
12
  each do |element, *rest|
20
13
  elements = rest.any? ? [element, *rest] : element
21
14
 
22
15
  output.push(elements)
23
- if matcher === elements || run == enum_count # rubocop:disable Style/CaseEquality
16
+ if matcher === output.last # rubocop:disable Style/CaseEquality
24
17
  yielder << output
25
18
  output = []
26
19
  end
20
+ end
21
+ yielder << output unless output.empty?
22
+ end
23
+ end
24
+
25
+ def slice_when
26
+ block = ::Proc.new
27
+
28
+ ::Enumerator.new do |yielder|
29
+ output = []
30
+ each do |element, *rest|
31
+ elements = rest.any? ? [element, *rest] : element
27
32
 
28
- run += 1
33
+ if output.empty? || !block.call(output.last, elements)
34
+ output.push(elements)
35
+ else
36
+ yielder << output
37
+ output = [elements]
38
+ end
29
39
  end
40
+ yielder << output unless output.empty?
30
41
  end
31
42
  end
32
43
  end
@@ -4,35 +4,19 @@ module Polyfill
4
4
  def chunk_while
5
5
  block = ::Proc.new
6
6
 
7
- enum_count =
8
- begin
9
- size
10
- rescue NameError
11
- count
12
- end
13
-
14
- return [self] if enum_count == 1
15
-
16
7
  ::Enumerator.new do |yielder|
17
8
  output = []
18
- each_cons(2).with_index(1) do |(a, b), run|
19
- if run == enum_count - 1
20
- if block.call(a, b)
21
- output.push(a, b)
22
- yielder << output
23
- else
24
- output.push(a)
25
- yielder << output
26
- yielder << [b]
27
- end
9
+ each do |element, *rest|
10
+ elements = rest.any? ? [element, *rest] : element
11
+
12
+ if output.empty? || block.call(output.last, elements)
13
+ output.push(elements)
28
14
  else
29
- output.push(a)
30
- unless block.call(a, b)
31
- yielder << output
32
- output = []
33
- end
15
+ yielder << output
16
+ output = [elements]
34
17
  end
35
18
  end
19
+ yielder << output unless output.empty?
36
20
  end
37
21
  end
38
22
 
@@ -1,6 +1,10 @@
1
+ require_relative 'numeric'
2
+
1
3
  module Polyfill
2
4
  module V2_4
3
5
  module Array
6
+ using Polyfill(Numeric: %w[#dup])
7
+
4
8
  def concat(*others)
5
9
  return super if others.length == 1
6
10
 
@@ -13,14 +17,10 @@ module Polyfill
13
17
  end
14
18
 
15
19
  def sum(init = 0)
16
- acc =
17
- begin
18
- init.dup
19
- rescue TypeError
20
- init
21
- end
20
+ acc = init.dup
22
21
 
23
- each do |elem|
22
+ for i in 0..(size - 1) # rubocop:disable Style/For
23
+ elem = self[i]
24
24
  acc += block_given? ? yield(elem) : elem
25
25
  end
26
26
 
@@ -1,6 +1,10 @@
1
+ require_relative 'numeric'
2
+
1
3
  module Polyfill
2
4
  module V2_4
3
5
  module Enumerable
6
+ using Polyfill(Numeric: %w[#dup])
7
+
4
8
  def chunk(*)
5
9
  return enum_for(:chunk) unless block_given?
6
10
 
@@ -8,12 +12,7 @@ module Polyfill
8
12
  end
9
13
 
10
14
  def sum(init = 0)
11
- acc =
12
- begin
13
- init.dup
14
- rescue TypeError
15
- init
16
- end
15
+ acc = init.dup
17
16
 
18
17
  each do |elem|
19
18
  acc += block_given? ? yield(elem) : elem
@@ -1,3 +1,3 @@
1
1
  module Polyfill
2
- VERSION = '0.7.0'.freeze
2
+ VERSION = '0.8.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: polyfill
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Lasseigne
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-04-22 00:00:00.000000000 Z
11
+ date: 2017-04-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler