Module: Gemmy::Patches

Defined in:
lib/gemmy/patches.rb

Overview

Gemmy provides patches for a few of the core classes.

Use Gemmy#load_globally to load these on the root namespace For a refinements-based approach, use this in a class/module definition:

Gemmy::Patches.class_refinements.each { |klass| using klass }

Note that there are nuances for how refinements are used. You can’t refer to the patches using define_method, for example.

See examples/01_using_as_refinement.rb for more info (linked from the README at github.com/maxpleaner/gemmy

Defined Under Namespace

Modules: ArrayPatch, ClassPatch, EnumeratorPatch, ExceptionPatch, FloatPatch, HashPatch, IntegerPatch, MethodPatch, ObjectPatch, ProcPatch, StringPatch, SymbolPatch, ThreadPatch

Class Method Summary collapse

Class Method Details

.autotestObject

searches for the ‘autotest’ method on any patch modules and runs it, checking that the return value is true raises an error if it’s not



19
20
21
22
23
24
25
# File 'lib/gemmy/patches.rb', line 19

def self.autotest
  class_refinements.each do |patch_klass|
    if patch_klass.respond_to?(:autotest)
      patch_klass.autotest || raise(RuntimeError, "#{patch_klass} failed")
    end
  end
end

.class_refinements(only: nil, except: nil) ⇒ Array<Class>

The usage of this method is to load all the patches for some core classes. With no arguments it will include all patches There are two optional params (keyword arguments).

Parameters:

  • only (Array<Symbol>) (defaults to: nil)

    if provided, will only patch those classes

  • except (Array<Symbol>) (defaults to: nil)

    if provided, will exclude those classes

Returns:

  • (Array<Class>)

    to be iteratively passed to ‘using’



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/gemmy/patches.rb', line 33

def self.class_refinements(only: nil, except: nil)
  return @@refined if defined? @@refined
  @@refined = core_patches.reduce([]) do |arr, (core_klass_sym, patch_klass)|
    next if only && !only.include?(core_klass_sym)
    next if except && except.include?(core_klass_sym)
    core_klass = const_get core_klass_sym.to_s
    class_patches = patch_klass.const_get "ClassMethods"
    instance_patches = patch_klass.const_get "InstanceMethods"
    class_patches.constants.each do |patch_class_sym|
      patch_class = class_patches.const_get patch_class_sym
      patch_as_class_method(core_klass, patch_class)
      arr.push patch_class
    end
    instance_patches.constants.each do |patch_class_sym|
      patch_class = instance_patches.const_get patch_class_sym
      patch_as_instance_method(core_klass, patch_class)
      arr.push patch_class
    end
    arr
  end.compact
  @@refined
end

.core_patchesObject



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/gemmy/patches.rb', line 98

def self.core_patches
  @@core_patches ||= {
    String: Gemmy::Patches::StringPatch,
    Symbol: Gemmy::Patches::SymbolPatch,
    Object: Gemmy::Patches::ObjectPatch,
    Array: Gemmy::Patches::ArrayPatch,
    Method: Gemmy::Patches::MethodPatch,
    Hash: Gemmy::Patches::HashPatch,
    Thread: Gemmy::Patches::ThreadPatch,
    Integer: Gemmy::Patches::IntegerPatch,
    Class: Gemmy::Patches::ClassPatch,
    Exception: Gemmy::Patches::ExceptionPatch,
    Float: Gemmy::Patches::FloatPatch,
    Proc: Gemmy::Patches::ProcPatch,
    Enumerator: Gemmy::Patches::EnumeratorPatch
  }.with_indifferent_access
end

.method_refinements(hash) ⇒ Object

Cherry pick methods to patch. To give an example:

Gemmy::Patches.method_refinements(
  Array: { InstanceMethods: [:Recurse, :KeyBy] }
).each { |r| using r }

Parameters:

  • hash (Hash)

    with a particular structure: top level keys are Symbols referring to core classes, i.e. :String top level values are hashes. second level keys are either :ClassMethods or :InstanceMethods

    referring to the scope
    

    second level values are arrays of symbols (one per method)



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/gemmy/patches.rb', line 70

def self.method_refinements(hash)
  hash.map do |core_klass_sym, patch_types|
    core_class = const_get(core_klass_sym)
    patch_types.map do |type_sym, patch_method_syms|
      patch_methods = core_patches[core_klass_sym].const_get type_sym.to_s
      patch_method_syms.map do |patch_method_sym|
        method_class = patch_methods.const_get(patch_method_sym)
        if type_sym == :InstanceMethods
          patch_as_instance_method(core_class, method_class)
        elsif type_sym == :ClassMethods
          patch_as_class_method(core_class, method_class)
        end
        method_class
      end
    end
  end.flatten.compact
end

.patch_as_class_method(core_klass, patch_klass) ⇒ Object



88
89
90
91
92
# File 'lib/gemmy/patches.rb', line 88

def self.patch_as_class_method(core_klass, patch_klass)
  patch_klass.send(:refine, core_klass.singleton_class) do
    include patch_klass
  end
end

.patch_as_instance_method(core_klass, patch_klass) ⇒ Object



94
95
96
# File 'lib/gemmy/patches.rb', line 94

def self.patch_as_instance_method(core_klass, patch_klass)
  patch_klass.send(:refine, core_klass) { include patch_klass }
end