Module: Corefines::Support::AliasSubmodules

Included in:
Array, Class, Enumerable, Hash, Module, Object, Corefines::String, Corefines::Symbol
Defined in:
lib/corefines/support/alias_submodules.rb

Overview

When this module is included, then it:

  1. Defines an “alias” for each submodule, i.e. singleton method that returns the submodule and it's named after the submodule, but the name is converted to underscore_separated or an operator. For example, instead of using Corefines::String::ToHtml one can write using Corefines::String::to_html.

  2. Includes all the submodules into the module. This allows to use all refinements inside the submodules just by using their parent module.

  3. Defines method AliasSubmodules.[].

Class Method Summary collapse

Class Method Details

.[](*names) ⇒ Module

Returns a new module that includes the named submodules.

Examples:

Corefines::Object[:blank?, :then]

Parameters:

  • names (Array<Symbol>)

    names of submodules aliases to include into the returned module.

Returns:

  • (Module)

    a new module that includes the named submodules.


26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/corefines/support/alias_submodules.rb', line 26

module AliasSubmodules

  OPERATORS_MAP = {
    :op_plus   => :[email protected],
    :op_minus  => :[email protected],
    :op_add    => :+,
    :op_sub    => :-,
    :op_pow    => :**,
    :op_mul    => :*,
    :op_div    => :/,
    :op_mod    => :%,
    :op_tilde  => :~,
    :op_cmp    => :<=>,
    :op_lshift => :<<,
    :op_rshift => :>>,
    :op_lt     => :<,
    :op_gt     => :>,
    :op_case   => :===,
    :op_equal  => :==,
    :op_apply  => :=~,
    :op_lt_eq  => :<=,
    :op_gt_eq  => :>=,
    :op_or     => :|,
    :op_and    => :&,
    :op_xor    => :^,
    :op_store  => :[]=,
    :op_fetch  => :[]
  }

  private

  def self.included(target)
    target.constants.each do |const|
      submodule = target.const_get(const)
      next unless submodule.instance_of? ::Module

      # Defines method-named "alias" for the submodule. (1)
      target.define_singleton_method(method_name(const)) { submodule }

      # Includes the submodule of the target into target. (2)
      target.send(:include, submodule)
    end

    target.extend ClassMethods
  end

  def self.method_name(module_name)
    name = underscore(module_name)
    OPERATORS_MAP[name.to_sym] || name
  end

  def self.underscore(camel_cased_word)
    return camel_cased_word unless camel_cased_word =~ /[A-Z]/

    camel_cased_word.to_s.dup.tap do |s|
      s.gsub! /([A-Z\d]+)([A-Z][a-z])/, '\1_\2'
      s.gsub! /([a-z\d])([A-Z])/, '\1_\2'
      s.downcase!
    end
  end


  module ClassMethods

    def [](*names)
      ::Module.new.tap do |mod|
        names.each do |mth|
          unless respond_to? mth
            fail ArgumentError, "no such refinements submodule with alias '#{mth}'"
          end
          mod.send(:include, public_send(mth))
        end
      end
    end
  end

  private_constant :ClassMethods, :OPERATORS_MAP
end