higher_expectations 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +4 -0
- data/License.txt +14 -0
- data/Manifest.txt +30 -0
- data/README.txt +155 -0
- data/Rakefile +4 -0
- data/config/hoe.rb +73 -0
- data/config/requirements.rb +15 -0
- data/lib/higher_expectations.rb +37 -0
- data/lib/instance_methods.rb +103 -0
- data/lib/version.rb +9 -0
- data/script/console +10 -0
- data/script/console.cmd +1 -0
- data/script/destroy +14 -0
- data/script/destroy.cmd +1 -0
- data/script/generate +14 -0
- data/script/generate.cmd +1 -0
- data/script/txt2html +82 -0
- data/script/txt2html.cmd +1 -0
- data/setup.rb +1585 -0
- data/spec/higher_expectations_spec.rb +27 -0
- data/spec/instance_methods_spec.rb +151 -0
- data/spec/spec_helper.rb +6 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/website.rake +17 -0
- data/test/test_helper.rb +2 -0
- data/test/test_higher_expectations.rb +11 -0
- data/website/index.html +11 -0
- data/website/index.txt +83 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +138 -0
- data/website/template.html.erb +48 -0
- metadata +82 -0
data/History.txt
ADDED
data/License.txt
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
Copyright (C) 2008 Justin Tyler Wiley
|
2
|
+
|
3
|
+
This program is free software: you can redistribute it and/or modify
|
4
|
+
it under the terms of the GNU General Public License as published by
|
5
|
+
the Free Software Foundation, either version 3 of the License, or
|
6
|
+
(at your option) any later version.
|
7
|
+
|
8
|
+
This program is distributed in the hope that it will be useful,
|
9
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
GNU General Public License for more details.
|
12
|
+
|
13
|
+
You should have received a copy of the GNU General Public License
|
14
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>
|
data/Manifest.txt
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
History.txt
|
2
|
+
License.txt
|
3
|
+
Manifest.txt
|
4
|
+
README.txt
|
5
|
+
Rakefile
|
6
|
+
config/hoe.rb
|
7
|
+
config/requirements.rb
|
8
|
+
lib/higher_expectations.rb
|
9
|
+
lib/instance_methods.rb
|
10
|
+
lib/version.rb
|
11
|
+
script/console
|
12
|
+
script/console.cmd
|
13
|
+
script/destroy
|
14
|
+
script/destroy.cmd
|
15
|
+
script/generate
|
16
|
+
script/generate.cmd
|
17
|
+
script/txt2html
|
18
|
+
script/txt2html.cmd
|
19
|
+
setup.rb
|
20
|
+
tasks/deployment.rake
|
21
|
+
tasks/environment.rake
|
22
|
+
tasks/website.rake
|
23
|
+
spec/higher_expectations_spec.rb
|
24
|
+
spec/instance_methods_spec.rb
|
25
|
+
spec/spec_helper.rb
|
26
|
+
website/index.html
|
27
|
+
website/index.txt
|
28
|
+
website/javascripts/rounded_corners_lite.inc.js
|
29
|
+
website/stylesheets/screen.css
|
30
|
+
website/template.html.erb
|
data/README.txt
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
= higher_expectations
|
2
|
+
|
3
|
+
* http://higher_expectations.rubyforge
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Provides an easy and quick way to make sure method arguments are what you expect them to be.
|
8
|
+
|
9
|
+
You want to make sure that methods explode if they are given inappropriate inputs, but you don't want to deal with a complete design-by-contract implementation like RDBC. Please note that this is nothing like a formal design-by-contract in any number of important ways. It provides something -like- the "obligations" component of DBC.
|
10
|
+
|
11
|
+
Writing explicit exception checking is tiring, redundant and error prone:
|
12
|
+
|
13
|
+
def calc_sunrise(day, month, year, latitude, longitude, planet)
|
14
|
+
raise Exception.new("day should be numeric and in the range of 1-32) unless day.kind_of?(Numeric) && day > 0 && day < 32
|
15
|
+
...etc. etc. ...
|
16
|
+
end
|
17
|
+
|
18
|
+
Higher expectations provides an easy and human readable alternative:
|
19
|
+
|
20
|
+
def calc_sunrise(day, month, year)
|
21
|
+
has_expectations(day, month)
|
22
|
+
day.must_not_be(Numeric).and_must_be_in_range(0..5)
|
23
|
+
month.must_be(Numeric)
|
24
|
+
...do other critical work below...
|
25
|
+
end
|
26
|
+
|
27
|
+
== FEATURES/PROBLEMS:
|
28
|
+
|
29
|
+
* Please note that this is alpha software
|
30
|
+
* Provides a set of usefull methods for determining what an object is at runtime, and raising an exception
|
31
|
+
* Avoids creating these methods in Object directly, and instead extends the objects passed in (although it does add them directly to Numeric due to constraints in Ruby's Numeric implementation)
|
32
|
+
* Allows for method changing and provides a dose of syntactic sugar
|
33
|
+
|
34
|
+
== SYNOPSIS:
|
35
|
+
|
36
|
+
Imagine you have a method to calculate sunrise buried within a 1D planet simulator codebase. Throughout the codebase, validations are used to check data input, and there is a well thought-out and well written test suite.
|
37
|
+
|
38
|
+
def calc_sunrise(day, month)
|
39
|
+
sunrise = (day - 50000)/month # arbitrary calculation that assumes day is a number and not negative
|
40
|
+
end
|
41
|
+
|
42
|
+
However, Joey your coworker hacks and calls the following function:
|
43
|
+
|
44
|
+
PlanetEarth.sunrise = calc_sunrise(-5, 1)
|
45
|
+
|
46
|
+
Code executes, no exceptions are raised, but earths sunrise changes to a weird value. No amount of unit testing, specing, validating outside the model would have stopped Joey from making this hambone maneuver.
|
47
|
+
|
48
|
+
Now you could have said something like:
|
49
|
+
|
50
|
+
def calc_sunrise(day, month)
|
51
|
+
raise ArgumentError.new("day must be numeric") unless day.kind_of?(Numeric)
|
52
|
+
raise ArgumentError.new("day must be in range of 1-31") unless day > 1 && day < 31
|
53
|
+
raise ArgumentError.new("month must be numeric") unless month.kind_of?(Numeric)
|
54
|
+
raise ArgumentError.new("month must be in range of 1-31") unless month > 1 && day < 31 # note subtle bug
|
55
|
+
raise ArgumentError.new("month must not be nil") unless month > 1 && month < 31
|
56
|
+
...sunrise calc...
|
57
|
+
end
|
58
|
+
|
59
|
+
Drudgery, duplication, error prone, etc. etc. Wouldn't you like to do this instead?
|
60
|
+
|
61
|
+
include HigherExpectations # somewhere in the class
|
62
|
+
def calc_sunrise(day, month)
|
63
|
+
has_expectations(day, month) # attach expectation methods to each object
|
64
|
+
day.must_be(Numeric) # day must be numeric or an exception will be raise
|
65
|
+
day.must_be_in_range(1..31) # day must be in range or exception
|
66
|
+
month.must_be(Numeric).and_must_be_in_range(1..31) # a neat combination of both
|
67
|
+
month.must_be_nil rescue nil # since it raises an exception, its trappable, allowing for more flexible handling
|
68
|
+
...sunrise calc
|
69
|
+
end
|
70
|
+
|
71
|
+
...or even cleaner.
|
72
|
+
|
73
|
+
def calc_sunrise(day,month)
|
74
|
+
has_expectations(day,month)
|
75
|
+
*args.map{|a| a.must_be(Numeric).and_must_be_in_range(1..31)}
|
76
|
+
month.must_be_nil
|
77
|
+
...sunrise calc...
|
78
|
+
end
|
79
|
+
|
80
|
+
See spec below for details on methods possible.
|
81
|
+
|
82
|
+
Copyright (c) 2008 Justin Tyler Wiley (justintylerwiley.com), under GPL V3
|
83
|
+
|
84
|
+
== SPEC:
|
85
|
+
|
86
|
+
HigherExpectations
|
87
|
+
- should not raise an exception when included
|
88
|
+
|
89
|
+
HigherExpectations#has_expectations
|
90
|
+
- should loop through given objects, extending each with instance_expectations.rb methods
|
91
|
+
|
92
|
+
InstanceMethods
|
93
|
+
|
94
|
+
InstanceMethods#raise_ae
|
95
|
+
- should raise an ArgumentException with the given message
|
96
|
+
|
97
|
+
InstanceMethods#must_be_/must_not_be_ - true, false, and nil
|
98
|
+
- should raise exception if expected to be true false or nil, and they are not
|
99
|
+
- should not raise exception if expected to be true false or nil, and they are
|
100
|
+
|
101
|
+
InstanceMethods#must_be and must_not_be a particular value
|
102
|
+
- should raise exception if item must be something and isnt
|
103
|
+
- should not raise exception if item must be something and IS
|
104
|
+
- (#not) should raise exception if item must not be something and IS
|
105
|
+
- (#not) should not raise exception if item must not be something and is not
|
106
|
+
|
107
|
+
InstanceMethods#must_be_a and must_not_be_a particular class of object
|
108
|
+
- should raise exception if item must be a class and isnt
|
109
|
+
- should not raise exception if item must be a class and IS
|
110
|
+
- (#not) should raise exception if item must not be a class and is not
|
111
|
+
- (#not) should not raise exception if item must not be a class and IS
|
112
|
+
|
113
|
+
InstanceMethods#must_be_in_range and must_not_be_in_range of numbers
|
114
|
+
- should raise exception if item must be in a range and isnt
|
115
|
+
- should not raise exception if item must be in a range and is
|
116
|
+
- (#not) should raise exception if item in a range
|
117
|
+
- (#not) should not raise exception if item not in range
|
118
|
+
- should raise HigherExpectation exception if handed something besides and array or a range
|
119
|
+
|
120
|
+
InstanceMethods#must_match and must_not_match a given pattern
|
121
|
+
- should raise exception if item does not match
|
122
|
+
- should not raise exception if item matches
|
123
|
+
- (#not) should not raise exception if item does not match
|
124
|
+
- (#not) should raise exception if item matches
|
125
|
+
|
126
|
+
InstanceMethods#must_respond_to and must_not_respond_to a given method
|
127
|
+
- should raise exception if item does not respond
|
128
|
+
- should not raise exception if item respond
|
129
|
+
- (#not) should raise exception if item responds
|
130
|
+
- (#not) should not raise exception if does respond
|
131
|
+
|
132
|
+
== REQUIREMENTS:
|
133
|
+
|
134
|
+
* hoe
|
135
|
+
|
136
|
+
== INSTALL:
|
137
|
+
|
138
|
+
* sudo gem install higher-expectations
|
139
|
+
|
140
|
+
== LICENSE:
|
141
|
+
|
142
|
+
Copyright (C) 2008 Justin Tyler Wiley
|
143
|
+
|
144
|
+
This program is free software: you can redistribute it and/or modify
|
145
|
+
it under the terms of the GNU General Public License as published by
|
146
|
+
the Free Software Foundation, either version 3 of the License, or
|
147
|
+
(at your option) any later version.
|
148
|
+
|
149
|
+
This program is distributed in the hope that it will be useful,
|
150
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
151
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
152
|
+
GNU General Public License for more details.
|
153
|
+
|
154
|
+
You should have received a copy of the GNU General Public License
|
155
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>
|
data/Rakefile
ADDED
data/config/hoe.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'higher_expectations/version'
|
2
|
+
|
3
|
+
AUTHOR = 'FIXME full name' # can also be an array of Authors
|
4
|
+
EMAIL = "FIXME email"
|
5
|
+
DESCRIPTION = "description of gem"
|
6
|
+
GEM_NAME = 'higher_expectations' # what ppl will type to install your gem
|
7
|
+
RUBYFORGE_PROJECT = 'higher_expectations' # The unix name for your project
|
8
|
+
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
9
|
+
DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
10
|
+
EXTRA_DEPENDENCIES = [
|
11
|
+
# ['activesupport', '>= 1.3.1']
|
12
|
+
] # An array of rubygem dependencies [name, version]
|
13
|
+
|
14
|
+
@config_file = "~/.rubyforge/user-config.yml"
|
15
|
+
@config = nil
|
16
|
+
RUBYFORGE_USERNAME = "unknown"
|
17
|
+
def rubyforge_username
|
18
|
+
unless @config
|
19
|
+
begin
|
20
|
+
@config = YAML.load(File.read(File.expand_path(@config_file)))
|
21
|
+
rescue
|
22
|
+
puts <<-EOS
|
23
|
+
ERROR: No rubyforge config file found: #{@config_file}
|
24
|
+
Run 'rubyforge setup' to prepare your env for access to Rubyforge
|
25
|
+
- See http://newgem.rubyforge.org/rubyforge.html for more details
|
26
|
+
EOS
|
27
|
+
exit
|
28
|
+
end
|
29
|
+
end
|
30
|
+
RUBYFORGE_USERNAME.replace @config["username"]
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
REV = nil
|
35
|
+
# UNCOMMENT IF REQUIRED:
|
36
|
+
# REV = YAML.load(`svn info`)['Revision']
|
37
|
+
VERS = HigherExpectations::VERSION::STRING + (REV ? ".#{REV}" : "")
|
38
|
+
RDOC_OPTS = ['--quiet', '--title', 'higher_expectations documentation',
|
39
|
+
"--opname", "index.html",
|
40
|
+
"--line-numbers",
|
41
|
+
"--main", "README",
|
42
|
+
"--inline-source"]
|
43
|
+
|
44
|
+
class Hoe
|
45
|
+
def extra_deps
|
46
|
+
@extra_deps.reject! { |x| Array(x).first == 'hoe' }
|
47
|
+
@extra_deps
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Generate all the Rake tasks
|
52
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
53
|
+
$hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
54
|
+
p.developer(AUTHOR, EMAIL)
|
55
|
+
p.description = DESCRIPTION
|
56
|
+
p.summary = DESCRIPTION
|
57
|
+
p.url = HOMEPATH
|
58
|
+
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
59
|
+
p.test_globs = ["test/**/test_*.rb"]
|
60
|
+
p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
|
61
|
+
|
62
|
+
# == Optional
|
63
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
64
|
+
#p.extra_deps = EXTRA_DEPENDENCIES
|
65
|
+
|
66
|
+
#p.spec_extras = {} # A hash of extra values to set in the gemspec.
|
67
|
+
end
|
68
|
+
|
69
|
+
CHANGES = $hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
|
70
|
+
PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
|
71
|
+
$hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
|
72
|
+
$hoe.rsync_args = '-av --delete --ignore-errors'
|
73
|
+
$hoe.spec.post_install_message = File.open(File.dirname(__FILE__) + "/../PostInstall.txt").read rescue ""
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
include FileUtils
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
%w[rake hoe newgem rubigen].each do |req_gem|
|
6
|
+
begin
|
7
|
+
require req_gem
|
8
|
+
rescue LoadError
|
9
|
+
puts "This Rakefile requires the '#{req_gem}' RubyGem."
|
10
|
+
puts "Installation: gem install #{req_gem} -y"
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
$:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
|
@@ -0,0 +1,37 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__)
|
2
|
+
require 'rubygems'
|
3
|
+
require 'instance_methods'
|
4
|
+
|
5
|
+
##
|
6
|
+
# Higher expectations module
|
7
|
+
# Provides method to load instance methods in a group of arguments
|
8
|
+
# Requires instance methods
|
9
|
+
#
|
10
|
+
# Usage:
|
11
|
+
#
|
12
|
+
# class Something
|
13
|
+
# include HigherExpectations
|
14
|
+
# end
|
15
|
+
# ..or optionally inject into Object (not recommended)
|
16
|
+
#
|
17
|
+
module HigherExpectations
|
18
|
+
VERSION = '0.1.0'
|
19
|
+
|
20
|
+
# Should be called at method entrance
|
21
|
+
# instead of spaming up entire Object class method space, extend each given object with expectation methods
|
22
|
+
def has_expectations(*objects)
|
23
|
+
objects.map do |obj|
|
24
|
+
begin
|
25
|
+
obj.extend(HigherExpectations::InstanceMethods)
|
26
|
+
# TypeErrors are generated when trying to extend Numeric objects, which are not and cannot be singeltons and hence cannot get new methods.
|
27
|
+
# Handled below via Numeric
|
28
|
+
rescue TypeError
|
29
|
+
next
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
alias :has_expectation :has_expectations
|
34
|
+
end
|
35
|
+
|
36
|
+
# Provides instance methods for Fixnum class, which due to limitiations mentioned above must be treated as a special case
|
37
|
+
class Fixnum; include HigherExpectations::InstanceMethods; end;
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module HigherExpectations
|
2
|
+
module InstanceMethods
|
3
|
+
# must_X functions raise the traditional "ArgumentException", this exception is for programic errors when using HigherExpectations
|
4
|
+
class HigherExpectationException < Exception; end;
|
5
|
+
|
6
|
+
# defines must_be and must_not_be nil, true, false
|
7
|
+
[true, false].each do |value|
|
8
|
+
send :define_method, "must_be_#{value.to_s}".to_sym, lambda {
|
9
|
+
raise_ae(" to be #{value.to_s}") unless self == value; self;
|
10
|
+
}
|
11
|
+
send :define_method, "must_not_be_#{value.to_s}".to_sym, lambda {
|
12
|
+
raise_ae(" to be #{value.to_s}") unless self != value; self;
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
# value must be nil, or must not be nil respectively
|
17
|
+
def must_be_nil; raise_ae(" to be nil") unless self == nil; end;
|
18
|
+
alias :and_must_be_nil :must_be_nil
|
19
|
+
def must_not_be_nil; raise_ae(" to be nil") unless self != nil; end;
|
20
|
+
alias :and_must_not_be_nil :must_not_be_nil
|
21
|
+
|
22
|
+
# raise ArgumentError exception
|
23
|
+
def raise_ae(message)
|
24
|
+
raise ArgumentError.new("Method expects this argument" + message.to_s)
|
25
|
+
end
|
26
|
+
|
27
|
+
# argument must be the given value
|
28
|
+
def must_be(*values)
|
29
|
+
values.each {|value| raise_ae(" must equal #{value}") unless self == value; }
|
30
|
+
self # allow for method concatonation "foo.must_be(String).and_must_not_be_nil
|
31
|
+
end
|
32
|
+
alias :and_must_be :must_be
|
33
|
+
|
34
|
+
# argument must NOT be the given value
|
35
|
+
def must_not_be(*values)
|
36
|
+
values.each {|value| raise_ae(" must NOT equal #{value}") unless self != value; }
|
37
|
+
self
|
38
|
+
end
|
39
|
+
alias :and_must_not_be :must_not_be
|
40
|
+
|
41
|
+
# value(s) must be a specific class or in given set of classes
|
42
|
+
def must_be_a(*klasses)
|
43
|
+
klasses.each do |klass|
|
44
|
+
raise_ae(" should be #{klass.to_s}") unless self.kind_of?(klass)
|
45
|
+
end
|
46
|
+
self
|
47
|
+
end
|
48
|
+
alias :and_must_be_a :must_be_a
|
49
|
+
|
50
|
+
# value(s) must not be in a specific class or set of klasses
|
51
|
+
def must_not_be_a(*klasses)
|
52
|
+
klasses.each do |klass|
|
53
|
+
raise_ae(" should NOT be #{klass.to_s}") if self.kind_of?(klass)
|
54
|
+
end
|
55
|
+
self
|
56
|
+
end
|
57
|
+
alias :and_must_not_be_a :must_not_be_a
|
58
|
+
|
59
|
+
# value(s) must be in a specific numeric range
|
60
|
+
def must_be_in_range(range)
|
61
|
+
raise HigherExpectationException.new("Must pass in two values ('foo.must_be_in_range(0,5)')") unless range.kind_of?(Range) || range.kind_of?(Array)
|
62
|
+
raise_ae("'s value to be in the range of #{range.first} to #{range.last} (it was #{self.to_s})") unless self >= range.first && self <= range.last
|
63
|
+
self
|
64
|
+
end
|
65
|
+
alias :and_must_be_in_range :must_be_in_range
|
66
|
+
|
67
|
+
# value(s) must be in a specific numeric range
|
68
|
+
def must_not_be_in_range(range)
|
69
|
+
raise HigherExpectationException.new("Must pass in two values ('foo.must_be_in_range(0,5)')") unless range.kind_of?(Range) || range.kind_of?(Array)
|
70
|
+
raise_ae("'s value NOT to be in the range of #{range.first} to #{range.last} (it was #{self.to_s})") if self >= range.first && self <= range.last
|
71
|
+
self
|
72
|
+
end
|
73
|
+
alias :and_must_not_be_in_range :must_not_be_in_range
|
74
|
+
|
75
|
+
def must_match(pattern)
|
76
|
+
raise_ae(" to match pattern #{pattern.to_s}") unless self =~ pattern
|
77
|
+
self
|
78
|
+
end
|
79
|
+
alias :and_must_match :must_match
|
80
|
+
|
81
|
+
def must_not_match(pattern)
|
82
|
+
raise_ae(" to match pattern #{pattern.to_s}") if self =~ pattern
|
83
|
+
self
|
84
|
+
end
|
85
|
+
alias :and_must_not_match :must_not_match
|
86
|
+
|
87
|
+
def must_respond_to(*meths)
|
88
|
+
meths.each do |meth|
|
89
|
+
raise_ae(" to respond to #{meth}") unless self.respond_to?(meth.to_s)
|
90
|
+
end
|
91
|
+
self
|
92
|
+
end
|
93
|
+
alias :and_must_respond_to :must_respond_to
|
94
|
+
|
95
|
+
def must_not_respond_to(*meths)
|
96
|
+
meths.each do |meth|
|
97
|
+
raise_ae(" to respond to #{meth}") if self.respond_to?(meth.to_s)
|
98
|
+
end
|
99
|
+
self
|
100
|
+
end
|
101
|
+
alias :and_must_not_respond_to :must_not_respond_to
|
102
|
+
end
|
103
|
+
end
|