Module: Interrobang

Defined in:
lib/interrobang.rb,
lib/interrobang/version.rb

Overview

Convert your ‘#predicate_methods?` to `#bang_methods!`

Constant Summary collapse

FalsePredicate =

Exception to raise when no block is provided for bangified falsey methods

Class.new(Exception)
DEFAULT_PATTERN =

Regexp that matches methods that end in question marks.

%r{\A[^?]+\?\z}
VERSION =
'1.1.0'

Class Method Summary collapse

Class Method Details

.bangify(*args, **keywords, &block) ⇒ Object

Wrapper method for ‘bangify_class` and `bangify_method`. The appropriate method will be called depending on the method signature.

Examples:

Interrobang.bangify(Answer) # => [:correct!]
Interrobang.bangify(Answer, :is_correct) # => :is_correct!

Returns:

  • either a Symbol or Symbol Array of bangified method names.



22
23
24
25
26
27
28
29
# File 'lib/interrobang.rb', line 22

def bangify(*args, **keywords, &block)
  klass, method = args
  if method
    bangify_method(klass, method, **keywords, &block)
  else
    bangify_class(klass, **keywords, &block)
  end
end

.bangify_class(klass, matching: DEFAULT_PATTERN, only: [], except: [], prefix: '', suffix: '', include_super: false) ⇒ Object

Converts the specified predicate methods in a class to bang methods.

Parameters:

  • klass

    The Class to target for bangification

  • block

    An optional block to run if a predicate method returns something falsey

Returns:

  • the Symbol Array of bangified method names.



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
# File 'lib/interrobang.rb', line 46

def bangify_class(klass, matching: DEFAULT_PATTERN, only: [], except: [], prefix: '', suffix: '', include_super: false)
  method_keys = klass.instance_methods(include_super)
  only = [only] unless only.is_a?(Array)
  except = [except] unless except.is_a?(Array)
  if only.empty?
    method_keys.map do |method_key|
      if method_key.to_s =~ matching && !except.include?(method_key)
        if block_given?
          bangify_method(klass, method_key, prefix: prefix, suffix: suffix, &Proc.new)
        else
          bangify_method(klass, method_key, prefix: prefix, suffix: suffix)
        end
      end
    end.compact
  else
    method_keys.map do |method_key|
      if only.include?(method_key)
        if block_given?
          bangify_method(klass, method_key, prefix: prefix, suffix: suffix, &Proc.new)
        else
          bangify_method(klass, method_key, prefix: prefix, suffix: suffix)
        end
      end
    end.compact
  end
end

.bangify_method(klass, predicate_method, prefix: '', suffix: '') ⇒ Object

Converts the specified predicate method to a bang method.

Parameters:

  • klass

    The Class to target for bangification

  • predicate_method

    The Symbol of the predicate method

  • block

    An optional block to run if a predicate method returns something falsey

Returns:

  • the Symbol name of the bang method created.



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/interrobang.rb', line 86

def bangify_method(klass, predicate_method, prefix: '', suffix: '')
  predicate_method_string = predicate_method.to_s
  method_name_base =
    case predicate_method_string[-1]
    when '=', '!'
      return
    when '?'
      predicate_method.to_s[0..-2]
    else
      predicate_method.to_s
    end

  bang_method = :"#{prefix}#{method_name_base}#{suffix}!"

  klass.class_eval do
    if block_given?
      define_method(bang_method) do |*args, &block|
        if send(predicate_method, *args, &block)
          true
        else
          yield(predicate_method)
        end
      end
    else
      define_method(bang_method) do |*args, &block|
        if send(predicate_method, *args, &block)
          true
        else
          raise(Interrobang::FalsePredicate, "#{predicate_method} is false")
        end
      end
    end
  end
  bang_method
end