lib/polyfill.rb in polyfill-0.7.0 vs lib/polyfill.rb in polyfill-0.8.0
- old
+ new
@@ -3,19 +3,121 @@
require 'polyfill/version'
require 'polyfill/utils'
module Polyfill
module Parcel; end
+
+ def get(module_name, methods, options = {})
+ if Object.const_get(module_name.to_s).is_a?(Class)
+ raise ArgumentError, "#{module_name} is a class not a module"
+ end
+
+ #
+ # parse options
+ #
+ versions = {
+ '2.2' => Polyfill::V2_2,
+ '2.3' => Polyfill::V2_3,
+ '2.4' => Polyfill::V2_4
+ }
+ desired_version = options.delete(:version) || versions.keys.max
+ unless versions.keys.include?(desired_version)
+ raise ArgumentError, "invalid value for keyword version: #{desired_version}"
+ end
+ versions.reject! do |version_number, _|
+ version_number > desired_version
+ end
+
+ unless options.empty?
+ raise ArgumentError, "unknown keyword: #{options.first[0]}"
+ end
+
+ #
+ # find all polyfills for the module across all versions
+ #
+ module_names = module_name.to_s.split('::')
+ current_ruby_version = RUBY_VERSION[/\A(\d+\.\d+)/, 1]
+
+ modules_with_updates = []
+ modules = []
+ versions.each do |version_number, version_module|
+ begin
+ final_module = module_names
+ .reduce(version_module) do |current_mod, name|
+ current_mod.const_get(name, false)
+ end
+
+ modules_with_updates << final_module
+
+ next if version_number <= current_ruby_version
+
+ modules << final_module.clone
+ rescue NameError
+ nil
+ end
+ end
+
+ if modules_with_updates.empty?
+ raise ArgumentError, %Q("#{module_name}" has no updates)
+ end
+
+ #
+ # remove methods that were not requested
+ #
+ methods_with_updates = modules_with_updates.flat_map(&:instance_methods).uniq
+ requested_methods = methods == :all ? methods_with_updates : methods
+
+ unless (leftovers = (requested_methods - methods_with_updates)).empty?
+ raise ArgumentError, %Q("##{leftovers.first}" is not a valid method on #{module_name} or has no updates)
+ end
+
+ modules.each do |instance_module|
+ instance_module.instance_methods.each do |name|
+ instance_module.send(:remove_method, name) unless requested_methods.include?(name)
+ end
+ end
+
+ #
+ # build the module to return
+ #
+ mod = Module.new
+
+ # make sure the methods get added if this module is included
+ mod.singleton_class.send(:define_method, :included) do |base|
+ modules.each do |module_to_add|
+ base.include module_to_add unless module_to_add.instance_methods.empty?
+ end
+ end
+
+ # make sure the methods get added if this module is extended
+ mod.singleton_class.send(:define_method, :extended) do |base|
+ modules.each do |module_to_add|
+ base.extend module_to_add unless module_to_add.instance_methods.empty?
+ end
+ end
+
+ Polyfill::Parcel.const_set("O#{mod.object_id}", mod)
+ end
+ module_function :get
end
def Polyfill(options = {}) # rubocop:disable Style/MethodName
mod = Module.new
#
# parse options
#
objects, others = options.partition { |key,| key[/\A[A-Z]/] }
+ objects.sort! do |a, b|
+ if !a.is_a?(Class) && b.is_a?(Class)
+ -1
+ elsif a.is_a?(Class) && !b.is_a?(Class)
+ 1
+ else
+ 0
+ end
+ end
others = others.to_h
versions = {
'2.2' => Polyfill::V2_2,
'2.3' => Polyfill::V2_3,
@@ -34,14 +136,13 @@
unless others.empty?
raise ArgumentError, "unknown keyword: #{others.first[0]}"
end
#
- # useful vars
+ # useful var
#
current_ruby_version = RUBY_VERSION[/\A(\d+\.\d+)/, 1]
- all_instance_modules = []
objects.each do |full_name, methods|
#
# find all polyfills for the object across all versions
#
@@ -61,11 +162,11 @@
end
end
.compact
if object_modules.empty?
- raise ArgumentError, %Q("#{full_name}" is not a valid class or has no updates)
+ raise ArgumentError, %Q("#{full_name}" is not a valid object or has no updates)
end
#
# get all class modules and instance modules from the polyfills
#
@@ -170,12 +271,10 @@
instance_module.send(:remove_method, name) unless requested_instance_methods.include?(name)
end
next if instance_module.instance_methods.empty?
- all_instance_modules << instance_module
-
mod.module_exec(requested_instance_methods) do |methods_added|
base_classes.each do |klass|
refine Object.const_get(klass) do
include instance_module
@@ -196,18 +295,9 @@
end
end
end
end
end
- end
- end
-
- #
- # make sure the includes get added if this module is included
- #
- mod.singleton_class.send(:define_method, :included) do |base|
- all_instance_modules.each do |instance_module|
- base.include instance_module
end
end
Polyfill::Parcel.const_set("O#{mod.object_id}", mod)
end