Class: Module

Inherits:
Object show all
Defined in:
lib/qualitysmith_extensions/module/bool_attr_accessor.rb,
lib/qualitysmith_extensions/module/guard_method.rb,
lib/qualitysmith_extensions/module/bool_attr_accessor.rb,
lib/qualitysmith_extensions/module/attribute_accessors.rb

Overview

Extends the module object with module and instance accessors for class attributes, just like the native attr* accessors for instance attributes.

Instance Method Summary collapse

Instance Method Details

#bool_attr_accessor(*args) ⇒ Object

This creates both a reader and a setter for a boolean (flag) attribute (instance variable).

bool_attr_accessor :a

is equivalent to

bool_attr_reader :a
bool_attr_setter :a

Examples:

x = Klass.new
x.a! true   # sets @a to true
x.a?        # => true
x.a!        # toggles @a, so that it ends up being false
x.a!        # toggles @a, so that it ends up being true
x.a! false  # sets @a to false


125
126
127
128
# File 'lib/qualitysmith_extensions/module/bool_attr_accessor.rb', line 125

def bool_attr_accessor(*args)
  bool_attr_reader *args
  bool_attr_setter *args
end

#bool_attr_reader(*args) ⇒ Object

This creates a reader method for a boolean (flag) attribute (instance variable).

bool_attr_reader :a

is equivalent to

def a?
  @a ? true : @a
end

Example:

class Foo
  def set_it
    @a = true
  end
end
x = Foo.new
x.a?        # => false
x.set_it
x.a?        # => true


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/qualitysmith_extensions/module/bool_attr_accessor.rb', line 39

def bool_attr_reader(*args)
  options = (if args.last.is_a?(Hash) then args.pop else {} end)    # These options aren't used here, per se, but it allows us to have bool_attr_accessor pass along same args to both bool_attr_reader and bool_attr_setter.

  make = {}
  args.each { |a|
    make["#{a}?".to_sym] = %{
      def #{a}?(true_value=true)
        @#{a} ? true_value : @#{a}
      end
    }
  }
  module_eval make.values.join("\n"), __FILE__, __LINE__

  make.keys
end

#bool_attr_setter(*args) ⇒ Object

This creates a setter method for a boolean (flag) attribute (instance variable).

bool_attr_setter :a

is equivalent to

def a!(switch=Exception)
  if switch == Exception
    @a = !@a
  else
    @a = switch ? true : false
    self
  end
end

This setter method can either be used to set it directly to true or false or to toggle it.

Examples:

x = Klass.new
x.a! true   # sets @a to true
x.a!        # toggles @a, so that it ends up being false
x.a!        # toggles @a, so that it ends up being true
x.a! false  # sets @a to false

Use :allow_nil if you want it to be a tri-state flag – that is, if you need to be able to set it to nil as well as true and false.

bool_attr_setter :a, :b, :allow_nil => true
x.a! nil  # sets @a to nil


83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/qualitysmith_extensions/module/bool_attr_accessor.rb', line 83

def bool_attr_setter(*args)
  options = (if args.last.is_a?(Hash) then args.pop else {} end)

  make = {}
  args.each { |a|
    make["#{a}!".to_sym] = %{
      def #{a}!(switch=Exception)
        if switch == Exception
          @#{a} = !@#{a}
        else
          #{
            options[:allow_nil] ?
              "@#{a} = switch ? true : switch" :
              "@#{a} = switch ? true : false"
          }
          self
        end
      end
    }
  }
  module_eval make.values.join("\n"), __FILE__, __LINE__
  make.keys
end

#guard_method(guard_method_name, guard_variable) ⇒ Object

A guard method (by this definition anyway) is a method that sets a flag, executes a block, and then returns the flag to its previous value. It ensures that the flag is set during the execution of the block.

In the simplest case, you’d use it like this:

class A
  guard_method :disable_stupid_stuff!, :@stupid_stuff_disabled
end
a = A.new
a.disable_stupid_stuff! do   # Causes @stupid_stuff_disabled to be set to true
  # Section of code during which you don't want any stupid stuff to happen
end                          # Causes @stupid_stuff_disabled to be set back to false
# Okay, a, you can resume doing stupid stuff again...

If you want your guard method to disable the flag rather than enable it, simply pass false to the guard method.

These calls can be nested however you wish:

a.guard_the_fruit! do
  a.guard_the_fruit!(false) do
    assert_equal false, a.guarding_the_fruit?
  end
  assert_equal true, a.guarding_the_fruit?
end

You can also use the guard methods as normal flag setter/clearer methods by simply not passing a block to it. Hence

a.guard_the_fruit!

will simply set @guarding_the_fruit to true, and

a.guard_the_fruit!(false)

will set @guarding_the_fruit to false.

Raises:

  • (ArgumentError)


53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/qualitysmith_extensions/module/guard_method.rb', line 53

def guard_method(guard_method_name, guard_variable)
  raise ArgumentError.new("Expected an instance variable name but got #{guard_variable}") if guard_variable !~ /^@([\w_]+)$/
  guard_variable.to_s =~ /^@([\w_]+)$/    # Why didn't the regexp above set $1 ??
  class_eval do
    bool_attr_accessor $1.to_sym
  end
  module_eval "    def \#{guard_method_name}(new_value = true, &block)\n      old_guard_state, \#{guard_variable} = \#{guard_variable}, new_value\n      if block_given?\n        begin\n          returning = yield\n        ensure\n          \#{guard_variable} = old_guard_state\n          returning\n        end\n      end\n    end\n  End\nend\n", __FILE__, __LINE__+1

#mattr_accessor(*syms) ⇒ Object



42
43
44
45
# File 'lib/qualitysmith_extensions/module/attribute_accessors.rb', line 42

def mattr_accessor(*syms)
  mattr_reader(*syms)
  mattr_writer(*syms)
end

#mattr_reader(*syms) ⇒ Object

:nodoc:



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/qualitysmith_extensions/module/attribute_accessors.rb', line 6

def mattr_reader(*syms)
  syms.each do |sym|
    class_eval("      unless defined? @@\#{sym}\n        @@\#{sym} = nil\n      end\n      \n      def self.\#{sym}\n        @@\#{sym}\n      end\n\n      def \#{sym}\n        @@\#{sym}\n      end\n    EOS\n  end\nend\n", __FILE__, __LINE__+1)

#mattr_writer(*syms) ⇒ Object



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/qualitysmith_extensions/module/attribute_accessors.rb', line 24

def mattr_writer(*syms)
  syms.each do |sym|
    class_eval("      unless defined? @@\#{sym}\n        @@\#{sym} = nil\n      end\n      \n      def self.\#{sym}=(obj)\n        @@\#{sym} = obj\n      end\n\n      def \#{sym}=(obj)\n        @@\#{sym} = obj\n      end\n    EOS\n  end\nend\n", __FILE__, __LINE__+1)

#mbool_attr_accessor(*args) ⇒ Object

This creates both a reader and a setter for a boolean (flag) class/module variable.

mbool_attr_accessor :a

is equivalent to

mbool_attr_reader :a
mbool_attr_setter :a

Works for both classes and modules.



221
222
223
224
# File 'lib/qualitysmith_extensions/module/bool_attr_accessor.rb', line 221

def mbool_attr_accessor(*args)
  mbool_attr_reader *args
  mbool_attr_setter *args
end

#mbool_attr_reader(*args) ⇒ Object

This creates a reader method for a boolean (flag) class/module variable.

mbool_attr_reader :a

is equivalent to

def self.a?
  @@a ? true : @@a
end

Works for both classes and modules.



147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/qualitysmith_extensions/module/bool_attr_accessor.rb', line 147

def mbool_attr_reader(*args)
  options = (if args.last.is_a?(Hash) then args.pop else {} end)    # These options aren't used here, per se, but it allows us to have bool_attr_accessor pass along same args to both bool_attr_reader and bool_attr_setter.

  make = {}
  args.each { |a|
    make["#{a}?".to_sym] = %{
      def self.#{a}?(true_value=true)
        @@#{a} ? true_value : @@#{a}
      end
    }
  }
  module_eval make.values.join("\n"), __FILE__, __LINE__
  make.keys
end

#mbool_attr_setter(*args) ⇒ Object

This creates a setter method for a boolean (flag) class/module variable.

mbool_attr_setter :a

is equivalent to

def self.a!(switch=Exception)
  if switch == Exception
    @@a = !@@a
  else
    @@a = switch ? true : false
    self
  end
end

Works for both classes and modules.

Use :allow_nil if you want it to be a tri-state flag – that is, if you need to be able to set it to nil as well as true and false.

mbool_attr_setter :a, :b, :allow_nil => true
C.a! nil  # sets @@a to nil


183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/qualitysmith_extensions/module/bool_attr_accessor.rb', line 183

def mbool_attr_setter(*args)
  options = (if args.last.is_a?(Hash) then args.pop else {} end)

  make = {}
  args.each { |a|
    # Initialize it first so that we won't have any NameErrors.
    module_eval %{ @@#{a} = nil if !defined?(@@#{a}) }, __FILE__, __LINE__

    make["#{a}!".to_sym] = %{
      def self.#{a}!(switch=Exception)
        if switch == Exception
          @@#{a} = !@@#{a}
        else
          #{
            options[:allow_nil] ?
              "@@#{a} = switch ? true : switch" :
              "@@#{a} = switch ? true : false"
          }
          self
        end
      end
    }
  }
  module_eval make.values.join("\n"), __FILE__, __LINE__
  make.keys
end

#mguard_method(guard_method_name, guard_variable) ⇒ Object

See the documentation for guard_method. mguard_method does the same thing, only it creates a class (or module) method rather than an instance method and it uses a class (or module) variable rather than an instance variable to store the guard state.

Example:

mguard_method :guard_the_fruit!, :@@guarding_the_fruit
mguard_method :use_assert_equal_with_highlight!, :@@always_use_assert_equal_with_highlight

Raises:

  • (ArgumentError)


81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/qualitysmith_extensions/module/guard_method.rb', line 81

def mguard_method(guard_method_name, guard_variable)
  raise ArgumentError.new("Expected a class variable name but got #{guard_variable}") if guard_variable !~ /^@@[\w_]+$/
  guard_variable.to_s =~ /^@@([\w_]+)$/
  class_eval do
    mbool_attr_accessor $1.to_sym
  end
  module_eval "    class << self\n      def \#{guard_method_name}(new_value = true, &block)\n        old_guard_state, \#{guard_variable} = \#{guard_variable}, new_value\n        if block_given?\n          begin\n            returning = yield\n          ensure\n            \#{guard_variable} = old_guard_state\n            returning\n          end\n        end\n      end\n    end\n  End\nend\n", __FILE__, __LINE__+1