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(StandardError)
DEFAULT_PATTERN =

Regexp that matches methods that end in question marks.

%r{\A[^?]+\?\z}
VERSION =
'1.2.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, &block) ⇒ 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
# File 'lib/interrobang.rb', line 46

def bangify_class(klass, matching: DEFAULT_PATTERN, only: [], except: [], prefix: '', suffix: '', include_super: false, &block)
  method_keys = klass.instance_methods(include_super)
  only = [only] unless only.is_a?(Array)
  except = [except] unless except.is_a?(Array)
  methods_to_bangify =
    if only.empty?
      (method_keys - except).select { |method_key| method_key.to_s =~ matching }
    else
      method_keys & only
    end
  methods_to_bangify.map do |method_key|
    bangify_method(klass, method_key, prefix: prefix, suffix: suffix, &block)
  end
end

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

Converts the specified predicate method to a bang method. Beware: bang methods will be created for undefined methods too. Assignment methods (‘method=`) and bang methods (`method!`) will not be converted.

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 or nil if the method was not bangified (ends in ‘!` or `=`.)



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
104
105
106
107
108
109
110
111
# File 'lib/interrobang.rb', line 77

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_string[0..-2]
    else
      predicate_method_string
    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
          fail Interrobang::FalsePredicate, "#{predicate_method} is false"
        end
      end
    end
  end
  bang_method
end