Module: SY::ExpressibleInUnits

Included in:
Magnitude
Defined in:
lib/sy/expressible_in_units.rb

Overview

This mixin provides ability to respond to SY unit symbol methods.

Defined Under Namespace

Modules: DetectRedefine

Constant Summary collapse

COLLISION_WARNING =
"Unit %s collision, method already defined on %s!"
REDEFINE_WARNING =
"Method %s being defined on %s shadows SY unit method!"
RecursionError =
Class.new StandardError

Class Method Summary collapse

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(ß, *args, &block) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/sy/expressible_in_units.rb', line 119

def method_missing ß, *args, &block
  return self if ß.to_s =~ /begin|end/ # 3rd party bug workaround
  super if ß.to_s =~ /to_.+/ # dissmiss :to_..., esp. :to_ary
  begin # prevent recurrent call of method_missing for the same symbol
    anti_recursion_exec token: ß, var: :@SY_Units_mmiss do
      prefixes, units, exps = parse_unit_symbol ß
      self.class.instance_variable_set "@no_collision", ß
      self.class.module_eval write_unit_method( ß, prefixes, units, exps )
      SY::ExpressibleInUnits.method_family << self.class.instance_method( ß )
    end
  rescue NameError => err
    super # give up
  rescue SY::ExpressibleInUnits::RecursionError
    super # give up
  else # actually invoke the method that we just defined
    send ß, *args, &block
  end
end

Class Method Details

.exponentiation_string(exp) ⇒ Object

Return exponentiation string (suffix) or empty ς if not necessary.



114
115
116
# File 'lib/sy/expressible_in_units.rb', line 114

def exponentiation_string exp
  exp == 1 ? '' : " ** #{exp}"
end

.find_unit(ς) ⇒ Object

Find unit based on name / abbreviation.



97
98
99
100
101
102
103
# File 'lib/sy/expressible_in_units.rb', line 97

def find_unit ς
  known_units.find do |u|
    u.name.to_s.downcase == ς.downcase &&
      ( ς == ς.downcase || ς == ς.upcase ) ||
      u.short.to_s == ς
  end
end

.included(receiver) ⇒ Object

#included hook of this module is set to perfom a casual check for blatant name collisions between SY::Unit-implied methods, and existing methods of the include receiver.



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/sy/expressible_in_units.rb', line 49

def included receiver
  included_in << receiver # keep track of where the mixin has been included
  # Warn if the receiver has potentially colliding methods.
  inst_methods = receiver.instance_methods
  w = COLLISION_WARNING % ["%s", receiver]
  known_units.each do |unit|
    next unless unit.warns?
    name, short = unit.name, unit.abbreviation
    warn w % "name method ##{name}" if inst_methods.include? name
    warn w % "abbreviation method ##{short}" if inst_methods.include? short
  end
  # Warn if shadowing methods are defined on the receiver later.
  if receiver.is_a? Class
    receiver.extend ::SY::ExpressibleInUnits::DetectRedefine
  end
end

.included_inObject

Modules in which this mixin has been included.



68
69
70
# File 'lib/sy/expressible_in_units.rb', line 68

def included_in
  @included_in ||= []
end

.known_unitsObject

Currently defined unit instances, if any.



83
84
85
86
87
# File 'lib/sy/expressible_in_units.rb', line 83

def known_units
  begin
    unit_namespace.instances
  rescue NoMethodError; [] end
end

.method_familyObject

All methods defined by this mixin.



91
92
93
# File 'lib/sy/expressible_in_units.rb', line 91

def method_family
  @method_family ||= []
end

.prefix_method_string(prefix) ⇒ Object

Return prefix method or empty string, if prefix method not necessary.



107
108
109
110
# File 'lib/sy/expressible_in_units.rb', line 107

def prefix_method_string prefix
  full_prefix = SY::PREFIX_TABLE.to_full( prefix )
  full_prefix == '' ? '' : ".#{full_prefix}"
end

.unit_namespaceObject

Unit namespace.



74
75
76
77
78
79
# File 'lib/sy/expressible_in_units.rb', line 74

def unit_namespace
  begin
    SY::Unit
  rescue NameError # no SY::Unit defined yet
  end
end

Instance Method Details

#respond_to_missing?(ß, *args, &block) ⇒ Boolean

Returns:

  • (Boolean)


138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/sy/expressible_in_units.rb', line 138

def respond_to_missing? ß, *args, &block
  # dismiss :to_... methods and /begin|end/ (3rd party bug workaround)
  return false if ß.to_s =~ /to_.+|begin|end/
  !! begin
    anti_recursion_exec token: ß, var: :@SY_Units_rmiss do
      parse_unit_symbol ß
    end
  rescue NameError, SY::ExpressibleInUnits::RecursionError
    false
  else
    true
  end
end