named-parameters 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +103 -102
- data/RELEASENOTES +11 -1
- data/Rakefile +10 -1
- data/VERSION +1 -1
- data/lib/named-parameters.rb +5 -1
- data/lib/named-parameters/module.rb +115 -37
- data/lib/named-parameters/object.rb +7 -3
- data/named-parameters.gemspec +12 -3
- data/spec/named-parameters_spec.rb +158 -29
- metadata +5 -5
data/README.md
CHANGED
@@ -1,143 +1,144 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
This gem enables/simulates named-parameters in Ruby.
|
1
|
+
This gem simulates named-parameters in Ruby. It's a complement to the common
|
2
|
+
Ruby idiom of using `Hash` args to emulate the use of named parameters.
|
4
3
|
|
5
|
-
|
6
|
-
|
4
|
+
It does this by extending the language with a `has_named_parameters` clause
|
5
|
+
that allows a class to declare the parameters that are acceptable to a method.
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
gem install named-parameters
|
7
|
+
The `has_named_parameters` dictates how the presence of these parameters are
|
8
|
+
enforced and raises an `ArgumentError` when a method invocation is made that
|
9
|
+
violates the rules for those parameters.
|
12
10
|
|
13
|
-
|
14
|
-
|
15
|
-
To enable it everywhere (recommended):
|
16
|
-
|
17
|
-
require 'named-parameters'
|
11
|
+
See: the [Named Parameter](http://en.wikipedia.org/wiki/named_parameter)
|
12
|
+
article from Wikipedia for more information.
|
18
13
|
|
19
|
-
|
14
|
+
Get It
|
15
|
+
------
|
16
|
+
You know you want it:
|
20
17
|
|
21
|
-
|
18
|
+
gem install named-parameters
|
22
19
|
|
23
|
-
|
20
|
+
Use It
|
21
|
+
------
|
22
|
+
Make it available everywhere:
|
24
23
|
|
24
|
+
require 'named-parameters'
|
25
|
+
|
26
|
+
But if you want to be selective, do:
|
27
|
+
|
25
28
|
require 'named-parameters/module'
|
26
29
|
|
27
|
-
|
28
|
-
example:
|
30
|
+
Then include the `NamedParameters` module into your class:
|
29
31
|
|
30
|
-
class
|
32
|
+
class YourClass
|
31
33
|
include NamedParameters
|
32
|
-
# ...
|
33
34
|
end
|
35
|
+
|
36
|
+
Either way, you would now be able to use the `has_named_parameters` clause
|
37
|
+
as needed:
|
34
38
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
class GoogleStorage
|
41
|
-
has_named_parameters :initialize,
|
42
|
-
:required => [ :'access-key', :'secret-key' ]
|
43
|
-
def initialize opts = { }
|
44
|
-
# ...
|
45
|
-
end
|
46
|
-
|
47
|
-
has_named_parameters :request, :optional => :timeout
|
48
|
-
def request path, opts = { }
|
49
|
-
# ...
|
39
|
+
class YourClass
|
40
|
+
has_named_parameters :your_method, :require => :param
|
41
|
+
def your_method options
|
42
|
+
puts options.inspect
|
50
43
|
end
|
51
44
|
end
|
52
|
-
|
53
|
-
Since the `GoogleStorage` class above declares that its initializer requires
|
54
|
-
`:'access-key'` and `:'secret-key'` to be specified, the following
|
55
|
-
invocation will (correctly) raise an `ArgumentError`
|
56
45
|
|
57
|
-
|
46
|
+
So when you invoke `your_method`, its parameter requirements will now be
|
47
|
+
enforced:
|
58
48
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
But specifying an unrecognized parameter will do:
|
49
|
+
obj = YourClass.new
|
50
|
+
obj.your_method :param => 'Et tu, Babe?' # will spit out: 'Et tu, Babe?'
|
51
|
+
obj.your_method # will raise an ArgumentError because the required :param was not specified
|
52
|
+
|
53
|
+
Abuse It
|
54
|
+
--------
|
55
|
+
Declare required parameters:
|
67
56
|
|
68
|
-
|
57
|
+
has_named_parameters :send_mail, :required => :to
|
58
|
+
has_named_parameters :send_mail, :required => [ :to, :subject ]
|
69
59
|
|
70
|
-
|
71
|
-
instance methods of a class:
|
72
|
-
|
73
|
-
class Point
|
74
|
-
has_named_parameters :initialize, :required => [ :x, :y ], :optional => :color
|
75
|
-
def initialize opts = { }
|
76
|
-
# ...
|
77
|
-
end
|
60
|
+
Declare optional parameters:
|
78
61
|
|
79
|
-
|
80
|
-
|
81
|
-
# ...
|
82
|
-
end
|
83
|
-
end
|
62
|
+
has_named_parameters :send_mail, :optional => :subject
|
63
|
+
has_named_parameters :send_mail, :optional => [ :subject, :bcc, :from ]
|
84
64
|
|
65
|
+
Declare one of a set of parameters as required (ie: require one and only
|
66
|
+
one from a list):
|
85
67
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
has_named_parameters :
|
68
|
+
has_named_parameters :send_mail, :oneof => [ :signature, :alias ]
|
69
|
+
|
70
|
+
Declare default values for optional parameters:
|
71
|
+
|
72
|
+
has_named_parameters :send_mail, :optional => [ :subject, :bcc, { :from => 'yourself@example.org' } ]
|
73
|
+
has_named_parameters :send_mail, :optional => [ :subject, :bcc, [ :from, 'yourself@example.org' ] ]
|
92
74
|
|
93
|
-
|
75
|
+
You can also declare default values for `:required` and `:oneof` parameters,
|
76
|
+
but really, that's just silly.
|
94
77
|
|
95
|
-
|
78
|
+
With `has_named_parameters`, you can mix-and-match parameter requirements:
|
96
79
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
called.
|
80
|
+
has_named_parameters :send_mail,
|
81
|
+
:required => [ :to, :subject, ],
|
82
|
+
:oneof => [ :signature, :alias ],
|
83
|
+
:optional => [ :subject, :bcc, [ :from, 'yourself@example.org' ] ]
|
102
84
|
|
103
|
-
|
104
|
-
following variations:
|
85
|
+
And is applicable to both class and instance methods:
|
105
86
|
|
106
|
-
|
107
|
-
|
87
|
+
require 'named-parameters'
|
88
|
+
|
89
|
+
class Mailer
|
90
|
+
has_named_parameters :send_mail,
|
91
|
+
:required => [ :to, :subject, ],
|
92
|
+
:oneof => [ :signature, :alias ],
|
93
|
+
:optional => [ :subject, :bcc, [ :from, 'yourself@example.org' ] ]
|
94
|
+
def send_mail options
|
95
|
+
# ... do send mail stuff here ...
|
96
|
+
end
|
97
|
+
|
98
|
+
has_named_parameters :archive, :optional => [ :method => 'zip' ]
|
99
|
+
def self.archive options = { }
|
100
|
+
# ... do mail archiving stuff here ...
|
101
|
+
end
|
108
102
|
end
|
109
103
|
|
110
|
-
|
111
|
-
|
112
|
-
|
104
|
+
Gotchas
|
105
|
+
-------
|
106
|
+
When `has_named_parameters` is declared in a class, it instruments the class
|
107
|
+
so that when the method in the declaration is invoked, a validation is
|
108
|
+
performed on the first `Hash` argument that was received by the method.
|
113
109
|
|
114
|
-
|
115
|
-
|
116
|
-
end
|
110
|
+
It really has no idea about the position of the argument that is supposed
|
111
|
+
to carry the named parameters.
|
117
112
|
|
118
|
-
|
113
|
+
So you can mix-and-match argument types in a method, and still declare that
|
114
|
+
it `has_named_parameters`:
|
119
115
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
# ...
|
116
|
+
has_named_parameters :request, :required => :accesskey
|
117
|
+
def request path, options
|
118
|
+
"path: #{path}, options: #{options.inspect}"
|
124
119
|
end
|
120
|
+
|
121
|
+
# invocation:
|
122
|
+
request "/xxx", :accesskey => '0925'
|
123
|
+
|
124
|
+
# result:
|
125
|
+
# => path: /xxx, options: {:accesskey => '0925'}
|
126
|
+
|
127
|
+
But be careful when you have something like the following:
|
125
128
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
# ...
|
129
|
+
has_named_parameters :request, :required => :accesskey
|
130
|
+
def request path, options = { }
|
131
|
+
"path: #{path}, options: #{options.inspect}"
|
130
132
|
end
|
131
133
|
|
132
|
-
#
|
133
|
-
|
134
|
-
def service opts
|
135
|
-
# ...
|
136
|
-
end
|
134
|
+
# invocation:
|
135
|
+
request :accesskey => '0925'
|
137
136
|
|
138
|
-
|
137
|
+
# result isn't what's expected:
|
138
|
+
# => path: {:accesskey => '0925'}, options: {}
|
139
139
|
|
140
|
-
|
140
|
+
The next release of the gem will adopt the convention of having the `Hash`
|
141
|
+
argument as the last argument passed to the method.
|
141
142
|
|
142
143
|
Dependencies
|
143
144
|
------------
|
data/RELEASENOTES
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
0.0.6 [Nov 13, 2010]
|
2
|
+
- [FEATURE] Added support for requiring one-of from a list of named
|
3
|
+
parameters.
|
4
|
+
- [FEATURE] Added support for declaring default values for parameters.
|
5
|
+
- [INTERNAL] spec is now normalized inside the has_named_parameters
|
6
|
+
declaration allowing more flexible notation when when specifying default
|
7
|
+
values for parameters.
|
8
|
+
- [INTERNAL] Updated tests.
|
9
|
+
|
1
10
|
0.0.5 [Nov 11, 2010]
|
2
11
|
--------------------
|
3
12
|
- [BUGFIX] Same as 0.0.4 - except this time it's really fixed :-)
|
@@ -8,7 +17,8 @@
|
|
8
17
|
|
9
18
|
0.0.3 [Nov 11, 2010]
|
10
19
|
--------------------
|
11
|
-
- Added support for has_named_parameter declaration for class
|
20
|
+
- [FEATURE] Added support for has_named_parameter declaration for class
|
21
|
+
methods.
|
12
22
|
|
13
23
|
0.0.2 [Nov 10, 2010]
|
14
24
|
--------------------
|
data/Rakefile
CHANGED
@@ -6,7 +6,16 @@ begin
|
|
6
6
|
Jeweler::Tasks.new do |gem|
|
7
7
|
gem.name = "named-parameters"
|
8
8
|
gem.summary = %Q{Poor man's named-parameters in Ruby}
|
9
|
-
gem.description = %Q{This gem
|
9
|
+
gem.description = %Q{This gem simulates named-parameters in Ruby. It's a complement to the common
|
10
|
+
Ruby idiom of using `Hash` args to emulate the use of named parameters.
|
11
|
+
|
12
|
+
It does this by extending the language with a `has_named_parameters` clause
|
13
|
+
that allows a class to declare the parameters that are acceptable to a method.
|
14
|
+
|
15
|
+
The `has_named_parameters` dictates how the presence of these parameters are
|
16
|
+
enforced and raises an `ArgumentError` when a method invocation is made that
|
17
|
+
violates the rules for those parameters.
|
18
|
+
}
|
10
19
|
gem.email = "jurisgalang@gmail.com"
|
11
20
|
gem.homepage = "http://github.com/jurisgalang/named-parameters"
|
12
21
|
gem.authors = ["Juris Galang"]
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.6
|
data/lib/named-parameters.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
-
#
|
2
|
-
#
|
1
|
+
# named-parameters.rb
|
2
|
+
#
|
3
|
+
# When mixed-in, the `NamedParameters` module adds has_named_parameters class
|
4
|
+
# method, which can be used to declare methods that are supposed to accepts
|
5
|
+
# named-parameters.
|
3
6
|
#
|
4
7
|
# Sample usage:
|
5
8
|
#
|
@@ -16,14 +19,10 @@
|
|
16
19
|
# FooBar.new :y => '...' # ArgumentError - since :x was not specified
|
17
20
|
#
|
18
21
|
# @author Juris Galang
|
22
|
+
# @copyright 2010 Juris Galang. All Rights Reserved
|
19
23
|
#
|
20
|
-
class Object
|
21
|
-
def eigenclass # :nodoc:
|
22
|
-
class << self; self; end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
24
|
module NamedParameters
|
25
|
+
protected
|
27
26
|
def self.included base # :nodoc:
|
28
27
|
base.extend ClassMethods
|
29
28
|
end
|
@@ -32,31 +31,47 @@ module NamedParameters
|
|
32
31
|
# this is the method used to validate the name of the received parameters
|
33
32
|
# (based on the defined spec) when an instrumented method is invoked.
|
34
33
|
#
|
35
|
-
def self.
|
36
|
-
|
37
|
-
spec[:optional]
|
34
|
+
def self.validate_specs name, params, spec # :nodoc:
|
35
|
+
mapper = lambda{ |n| n.instance_of?(Hash) ? n.keys.first : n }
|
36
|
+
optional = spec[:optional].map &mapper
|
37
|
+
required = spec[:required].map &mapper
|
38
|
+
oneof = spec[:oneof].map &mapper
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
} ]
|
40
|
+
# determine what keys are allowed
|
41
|
+
order = lambda{ |x, y| x.to_s <=> y.to_s }
|
42
|
+
allowed = (optional + required + oneof).sort &order
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
keys
|
47
|
-
|
48
|
-
keys.sort! &
|
49
|
-
|
44
|
+
# determine what keys were passed;
|
45
|
+
# also, plugin the names of parameters assigned with default values
|
46
|
+
#keys = (params.keys.map{ |k| k.to_sym } + defaults.keys).uniq
|
47
|
+
keys = params.keys.map{ |k| k.to_sym }
|
48
|
+
keys.sort! &order
|
49
|
+
required.sort! &order
|
50
50
|
|
51
|
+
# this lambda is used to present the list of parameters as a string
|
51
52
|
list = lambda{ |params| params.join(", ") }
|
53
|
+
|
54
|
+
# require that all of :required parameters are specified
|
55
|
+
unless required.empty?
|
56
|
+
k = required & keys
|
57
|
+
raise ArgumentError, \
|
58
|
+
"#{name} requires the following parameters: #{list[required - k]}" \
|
59
|
+
unless k == required
|
60
|
+
end
|
52
61
|
|
53
|
-
|
54
|
-
|
62
|
+
# require that one (and only one) of :oneof parameters is specified
|
63
|
+
unless oneof.empty?
|
64
|
+
k = oneof & keys
|
65
|
+
raise ArgumentError, \
|
66
|
+
"#{name} requires at least one of the following parameters: #{list[oneof]}" \
|
67
|
+
if k.empty?
|
55
68
|
raise ArgumentError, \
|
56
|
-
"#{name}
|
57
|
-
|
69
|
+
"#{name} may specify only one of the following parameters: #{list[oneof]}" \
|
70
|
+
if k.length > 1
|
58
71
|
end
|
59
72
|
|
73
|
+
# enforce that only declared parameters (:required, :optional, and :oneof)
|
74
|
+
# may be specified
|
60
75
|
k = keys - allowed
|
61
76
|
raise ArgumentError, \
|
62
77
|
"Unrecognized parameter specified on call to #{name}: #{list[k]}" \
|
@@ -64,28 +79,74 @@ module NamedParameters
|
|
64
79
|
end
|
65
80
|
|
66
81
|
module ClassMethods
|
67
|
-
protected
|
68
82
|
# Declares that `method` will enforce named parameters behavior as
|
69
|
-
# described in `spec`; a method declared with
|
70
|
-
# parameters will raise an `ArgumentError` if it is invoked
|
71
|
-
# required parameters or receives an unrecognized parameter.
|
83
|
+
# described in `spec`; a method declared with `:required` and/or
|
84
|
+
# `:optional` parameters will raise an `ArgumentError` if it is invoked
|
85
|
+
# without its required parameters or receives an unrecognized parameter.
|
72
86
|
#
|
73
87
|
# Sample usage:
|
74
88
|
#
|
75
|
-
# has_named_parameters :point, :required => [ :x, :y ],
|
76
|
-
# :optional => :color
|
89
|
+
# has_named_parameters :point, :required => [ :x, :y ], :optional => :color
|
77
90
|
#
|
78
|
-
# @param [Symbol]
|
91
|
+
# @param [Symbol] method the name of the method that is supposed to
|
79
92
|
# enforce named parameters behavior.
|
80
93
|
#
|
81
|
-
# @param [Hash]
|
94
|
+
# @param [Hash] spec a `Hash` to specify the list of required and optional
|
95
|
+
# parameters for the method. Use either the `:required`, `:optional`, or
|
96
|
+
# `:oneof` key to specify the lists of parameters. The list is expected
|
97
|
+
# to be an `Array` of symbols matching the names of the expected and
|
98
|
+
# optional parameters.
|
82
99
|
#
|
83
|
-
#
|
100
|
+
# Parameters are evaluated according their classification:
|
101
|
+
#
|
102
|
+
# * `:required` means that all of these parameters must be specified.
|
103
|
+
# * `:optional` means that all or none of these parameters may be used.
|
104
|
+
# * `:oneof` means that one of these parameters must be specified.
|
84
105
|
#
|
85
106
|
def has_named_parameters method, spec = { }
|
107
|
+
# ensure spec entries are initialized and the proper types
|
108
|
+
[ :required, :optional, :oneof ].each{ |k| spec[k] ||= [] }
|
109
|
+
spec = Hash[ spec.map{ |k, v|
|
110
|
+
v = [ v ] unless v.instance_of? Array
|
111
|
+
v.map!{ |entry| entry.instance_of?(Array) ? Hash[*entry] : entry }
|
112
|
+
[ k, v ]
|
113
|
+
} ]
|
86
114
|
specs[method] = spec
|
87
115
|
end
|
88
116
|
|
117
|
+
protected
|
118
|
+
# Attach a validation block for a specific parameter that will be invoked
|
119
|
+
# before the actual `method` call.
|
120
|
+
#
|
121
|
+
# @param [Symbol] method the name of the method.
|
122
|
+
#
|
123
|
+
# @param [Symbol] param the name of the parameter whose value is to be
|
124
|
+
# validated.
|
125
|
+
#
|
126
|
+
# @param [lambda, Proc] &block the chunk of code that will perform the
|
127
|
+
# actual validation. It is expected to raise an error or return false
|
128
|
+
# if the validation fails. It receives argument for `param` on
|
129
|
+
# invocation.
|
130
|
+
#
|
131
|
+
# If `&block` is not specified then it assumes that an implicit
|
132
|
+
# validation method is defined. It calculates the name of this method
|
133
|
+
# by concatenating the values supplied for `method` and `param`,
|
134
|
+
# suffixed with the word `validation`, eg:
|
135
|
+
#
|
136
|
+
# validates_arguments_for :request, :timeout
|
137
|
+
# def request, opts = { }
|
138
|
+
# ...
|
139
|
+
# end
|
140
|
+
#
|
141
|
+
# private
|
142
|
+
# def request_timeout_validation value
|
143
|
+
# ...
|
144
|
+
# end
|
145
|
+
#
|
146
|
+
def validates_arguments method, param, &block
|
147
|
+
# TODO: IMPLEMENT
|
148
|
+
end
|
149
|
+
|
89
150
|
# add instrumentation for class methods
|
90
151
|
def singleton_method_added name # :nodoc:
|
91
152
|
instrument name do
|
@@ -122,10 +183,27 @@ module NamedParameters
|
|
122
183
|
|
123
184
|
# insert parameter validation prior to executing the instrumented method
|
124
185
|
def intercept method, owner, name, spec # :nodoc:
|
186
|
+
fullname = "#{owner}#{name}"
|
125
187
|
define_method name do |*args, &block|
|
126
|
-
|
127
|
-
|
128
|
-
|
188
|
+
# locate the argument representing the named parameters value
|
189
|
+
# for the method invocation
|
190
|
+
params = args.find{ |arg| arg.instance_of? Hash }
|
191
|
+
args << (params = { }) if params.nil?
|
192
|
+
|
193
|
+
# merge the declared default values for params into the arguments
|
194
|
+
# used when the method is invoked
|
195
|
+
defaults = { }
|
196
|
+
spec.each do |k, v|
|
197
|
+
v.each{ |entry| defaults.merge! entry if entry.instance_of? Hash }
|
198
|
+
end
|
199
|
+
params = defaults.merge params
|
200
|
+
|
201
|
+
# validate the parameters against the spec
|
202
|
+
NamedParameters::validate_specs fullname, params, spec
|
203
|
+
|
204
|
+
# inject the updated argument values for params into the arguments
|
205
|
+
# before actually making method invocation
|
206
|
+
args.map!{ |arg| arg.instance_of?(Hash) ? params : arg }
|
129
207
|
method.bind(self).call(*args, &block)
|
130
208
|
end
|
131
209
|
end
|
data/named-parameters.gemspec
CHANGED
@@ -5,12 +5,21 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{named-parameters}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.6"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Juris Galang"]
|
12
|
-
s.date = %q{2010-11-
|
13
|
-
s.description = %q{This gem
|
12
|
+
s.date = %q{2010-11-13}
|
13
|
+
s.description = %q{This gem simulates named-parameters in Ruby. It's a complement to the common
|
14
|
+
Ruby idiom of using `Hash` args to emulate the use of named parameters.
|
15
|
+
|
16
|
+
It does this by extending the language with a `has_named_parameters` clause
|
17
|
+
that allows a class to declare the parameters that are acceptable to a method.
|
18
|
+
|
19
|
+
The `has_named_parameters` dictates how the presence of these parameters are
|
20
|
+
enforced and raises an `ArgumentError` when a method invocation is made that
|
21
|
+
violates the rules for those parameters.
|
22
|
+
}
|
14
23
|
s.email = %q{jurisgalang@gmail.com}
|
15
24
|
s.extra_rdoc_files = [
|
16
25
|
"README.md"
|
@@ -2,45 +2,174 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
2
|
|
3
3
|
describe "NamedParameters" do
|
4
4
|
before :all do
|
5
|
-
class
|
5
|
+
class Foo
|
6
6
|
has_named_parameters :initialize, :required => :x, :optional => [ :y, :z ]
|
7
|
-
def initialize
|
7
|
+
def initialize opts = {}; end
|
8
8
|
|
9
9
|
has_named_parameters :method_one, :required => :x, :optional => [ :y, :z ]
|
10
|
-
def method_one
|
10
|
+
def method_one x, y, opts = {}; end
|
11
11
|
|
12
|
-
def method_two
|
12
|
+
def method_two x, y, opts = {}; end
|
13
|
+
|
14
|
+
has_named_parameters :method_three, :required => :x, :optional => [ :y, :z ]
|
15
|
+
def self.method_three x, y, opts = {}; end
|
16
|
+
|
17
|
+
def self.method_four x, y, opts = {}; end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Bar
|
21
|
+
has_named_parameters :method_with_one_required, :required => :x
|
22
|
+
def method_with_one_required opts = {}; end
|
23
|
+
|
24
|
+
has_named_parameters :method_with_many_required, :required => [ :x, :y ]
|
25
|
+
def method_with_many_required opts = {}; end
|
26
|
+
|
27
|
+
has_named_parameters :method_with_one_oneof, :oneof => :x
|
28
|
+
def method_with_one_oneof opts = {}; end
|
29
|
+
|
30
|
+
has_named_parameters :method_with_many_oneof, :oneof => [ :x, :y ]
|
31
|
+
def method_with_many_oneof opts = {}; end
|
32
|
+
|
33
|
+
has_named_parameters :method_with_one_optional, :optional => :x
|
34
|
+
def method_with_one_optional opts = {}; end
|
35
|
+
|
36
|
+
has_named_parameters :method_with_many_optional, :optional => [ :x, :y ]
|
37
|
+
def method_with_many_optional opts = {}; end
|
38
|
+
|
39
|
+
has_named_parameters :method_with_one_of_each_requirement, :required => :w, :oneof => [ :x, :y ], :optional => :z
|
40
|
+
def method_with_one_of_each_requirement opts = {}; end
|
13
41
|
end
|
14
42
|
end
|
15
43
|
|
16
44
|
it "should allow declaration of has_named_parameters" do
|
17
|
-
|
45
|
+
Foo.should respond_to :has_named_parameters
|
18
46
|
end
|
19
47
|
|
20
48
|
it "should enforce named parameters for constructor" do
|
21
|
-
lambda{
|
22
|
-
lambda{
|
23
|
-
lambda{
|
24
|
-
lambda{
|
25
|
-
lambda{
|
26
|
-
end
|
27
|
-
|
28
|
-
it "should enforce named parameters for instrumented methods" do
|
29
|
-
lambda{ @
|
30
|
-
lambda{ @
|
31
|
-
lambda{ @
|
32
|
-
lambda{ @
|
33
|
-
lambda{ @
|
34
|
-
lambda{ @
|
35
|
-
lambda{ @
|
36
|
-
lambda{ @
|
37
|
-
lambda{ @
|
38
|
-
end
|
39
|
-
|
40
|
-
it "should not enforce named parameters for un-instrumented methods" do
|
41
|
-
lambda{ @
|
42
|
-
lambda{ @
|
43
|
-
lambda{ @
|
44
|
-
lambda{ @
|
49
|
+
lambda{ Foo.new }.should raise_error ArgumentError
|
50
|
+
lambda{ Foo.new :w => :w }.should raise_error ArgumentError
|
51
|
+
lambda{ Foo.new :x => :x }.should_not raise_error
|
52
|
+
lambda{ Foo.new :x => :x, :y => :y }.should_not raise_error
|
53
|
+
lambda{ Foo.new :x => :x, :y => :y, :z => :z }.should_not raise_error
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should enforce named parameters for instrumented instance methods" do
|
57
|
+
lambda{ @foo = Foo.new :x => :x, :y => :y, :z => :z }.should_not raise_error
|
58
|
+
lambda{ @foo.method_one :x }.should raise_error ArgumentError
|
59
|
+
lambda{ @foo.method_one :x, :y }.should raise_error ArgumentError
|
60
|
+
lambda{ @foo.method_one :x, :y, :x => :x, :y => :y, :z => :z, :w => :w }.should raise_error ArgumentError
|
61
|
+
lambda{ @foo.method_one :x => :x, :y => :y, :z => :z }.should raise_error ArgumentError
|
62
|
+
lambda{ @foo.method_one :x, :y, :w => :w }.should raise_error ArgumentError
|
63
|
+
lambda{ @foo.method_one :x, :y, :x => :x }.should_not raise_error
|
64
|
+
lambda{ @foo.method_one :x, :y, :x => :x, :y => :y }.should_not raise_error
|
65
|
+
lambda{ @foo.method_one :x, :y, :x => :x, :y => :y, :z => :z }.should_not raise_error
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should not enforce named parameters for un-instrumented instance methods" do
|
69
|
+
lambda{ @foo = Foo.new :x => :x, :y => :y, :z => :z }.should_not raise_error
|
70
|
+
lambda{ @foo.method_two :x }.should raise_error ArgumentError
|
71
|
+
lambda{ @foo.method_two :x, :y }.should_not raise_error ArgumentError
|
72
|
+
lambda{ @foo.method_two :x, :y, :w => :w }.should_not raise_error ArgumentError
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should enforce named parameters for instrumented class methods" do
|
76
|
+
lambda{ Foo.method_three :x }.should raise_error ArgumentError
|
77
|
+
lambda{ Foo.method_three :x, :y }.should raise_error ArgumentError
|
78
|
+
lambda{ Foo.method_three :x, :y, :x => :x, :y => :y, :z => :z, :w => :w }.should raise_error ArgumentError
|
79
|
+
lambda{ Foo.method_three :x => :x, :y => :y, :z => :z }.should raise_error ArgumentError
|
80
|
+
lambda{ Foo.method_three :x, :y, :w => :w }.should raise_error ArgumentError
|
81
|
+
lambda{ Foo.method_three :x, :y, :x => :x }.should_not raise_error
|
82
|
+
lambda{ Foo.method_three :x, :y, :x => :x, :y => :y }.should_not raise_error
|
83
|
+
lambda{ Foo.method_three :x, :y, :x => :x, :y => :y, :z => :z }.should_not raise_error
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should not enforce named parameters for un-instrumented class methods" do
|
87
|
+
lambda{ Foo.method_four :x }.should raise_error ArgumentError
|
88
|
+
lambda{ Foo.method_four :x, :y }.should_not raise_error ArgumentError
|
89
|
+
lambda{ Foo.method_four :x, :y, :w => :w }.should_not raise_error ArgumentError
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should require all :required parameters" do
|
93
|
+
bar = Bar.new
|
94
|
+
lambda{ bar.method_with_one_required }.should raise_error ArgumentError
|
95
|
+
lambda{ bar.method_with_one_required :a => :a }.should raise_error ArgumentError
|
96
|
+
lambda{ bar.method_with_one_required :x => :x }.should_not raise_error
|
97
|
+
|
98
|
+
lambda{ bar.method_with_many_required }.should raise_error ArgumentError
|
99
|
+
lambda{ bar.method_with_many_required :x => :x }.should raise_error ArgumentError
|
100
|
+
lambda{ bar.method_with_many_required :x => :x, :y => :y }.should_not raise_error
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should require one and only one of :oneof parameters" do
|
104
|
+
bar = Bar.new
|
105
|
+
lambda{ bar.method_with_one_oneof }.should raise_error ArgumentError
|
106
|
+
lambda{ bar.method_with_one_oneof :a => :a }.should raise_error ArgumentError
|
107
|
+
lambda{ bar.method_with_one_oneof :x => :x }.should_not raise_error
|
108
|
+
|
109
|
+
lambda{ bar.method_with_many_oneof }.should raise_error ArgumentError
|
110
|
+
lambda{ bar.method_with_many_oneof :a => :a }.should raise_error ArgumentError
|
111
|
+
lambda{ bar.method_with_many_oneof :x => :x }.should_not raise_error
|
112
|
+
lambda{ bar.method_with_many_oneof :y => :y }.should_not raise_error
|
113
|
+
lambda{ bar.method_with_many_oneof :x => :x, :y => :y }.should raise_error ArgumentError
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should reject parameters not declared in :required, :optional, or :oneof" do
|
117
|
+
bar = Bar.new
|
118
|
+
lambda{ bar.method_with_one_optional }.should_not raise_error
|
119
|
+
lambda{ bar.method_with_one_optional :x => :x }.should_not raise_error
|
120
|
+
lambda{ bar.method_with_one_optional :a => :a }.should raise_error ArgumentError
|
121
|
+
lambda{ bar.method_with_one_optional :x => :x, :y => :y }.should raise_error ArgumentError
|
122
|
+
|
123
|
+
lambda{ bar.method_with_many_optional }.should_not raise_error
|
124
|
+
lambda{ bar.method_with_many_optional :x => :x }.should_not raise_error
|
125
|
+
lambda{ bar.method_with_many_optional :y => :y }.should_not raise_error
|
126
|
+
lambda{ bar.method_with_many_optional :x => :x, :y => :y }.should_not raise_error
|
127
|
+
lambda{ bar.method_with_many_optional :x => :x, :y => :y, :z => :z }.should raise_error ArgumentError
|
128
|
+
|
129
|
+
lambda{ bar.method_with_one_of_each_requirement }.should raise_error ArgumentError
|
130
|
+
lambda{ bar.method_with_one_of_each_requirement :w => :w }.should raise_error ArgumentError
|
131
|
+
lambda{ bar.method_with_one_of_each_requirement :w => :w, :x => :x }.should_not raise_error
|
132
|
+
lambda{ bar.method_with_one_of_each_requirement :w => :w, :y => :y }.should_not raise_error
|
133
|
+
lambda{ bar.method_with_one_of_each_requirement :w => :w, :x => :x, :y => :y }.should raise_error ArgumentError
|
134
|
+
lambda{ bar.method_with_one_of_each_requirement :w => :w, :x => :x, :z => :z }.should_not raise_error
|
135
|
+
lambda{ bar.method_with_one_of_each_requirement :w => :w, :y => :y, :z => :z }.should_not raise_error
|
136
|
+
lambda{ bar.method_with_one_of_each_requirement :w => :w, :x => :x, :z => :z, :a => :a }.should raise_error ArgumentError
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should be able to supply the default values for optional parameters" do
|
140
|
+
class Zoo
|
141
|
+
has_named_parameters :method_with_one_optional_parameter, :optional => { :x => 1 }
|
142
|
+
def method_with_one_optional_parameter opts = { }; opts[:x]; end
|
143
|
+
|
144
|
+
has_named_parameters :method_with_many_optional_parameters, :optional => [ [ :x, 1 ], [ :y, 2 ] ]
|
145
|
+
def method_with_many_optional_parameters opts = { }; opts[:x] + opts[:y]; end
|
146
|
+
|
147
|
+
has_named_parameters :method_with_many_optional_parameters_too, :optional => [ { :x => 1 }, { :y => 2 } ]
|
148
|
+
def method_with_many_optional_parameters_too opts = { }; opts[:x] + opts[:y]; end
|
149
|
+
end
|
150
|
+
|
151
|
+
zoo = Zoo.new
|
152
|
+
zoo.method_with_one_optional_parameter.should eql 1
|
153
|
+
zoo.method_with_one_optional_parameter(:x => 2).should eql 2
|
154
|
+
|
155
|
+
zoo.method_with_many_optional_parameters.should eql 3
|
156
|
+
zoo.method_with_many_optional_parameters(:x => 2).should eql 4
|
157
|
+
zoo.method_with_many_optional_parameters(:x => 2, :y => 3).should eql 5
|
158
|
+
|
159
|
+
zoo.method_with_many_optional_parameters_too.should eql 3
|
160
|
+
zoo.method_with_many_optional_parameters_too(:x => 2).should eql 4
|
161
|
+
zoo.method_with_many_optional_parameters_too(:x => 2, :y => 3).should eql 5
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should be able to instrument the class method new" do
|
165
|
+
class Quux
|
166
|
+
has_named_parameters :new, :required => :x
|
167
|
+
def self.new opts = { }; end
|
168
|
+
def initialize opts = { }; end
|
169
|
+
end
|
170
|
+
lambda { Quux.new }.should raise_error ArgumentError
|
171
|
+
lambda { Quux.new :y => :y }.should raise_error ArgumentError
|
172
|
+
lambda { Quux.new :x => :x, :y => :y }.should raise_error ArgumentError
|
173
|
+
lambda { Quux.new :x => :x }.should_not raise_error
|
45
174
|
end
|
46
175
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: named-parameters
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 6
|
10
|
+
version: 0.0.6
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Juris Galang
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-11-
|
18
|
+
date: 2010-11-13 00:00:00 -08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -48,7 +48,7 @@ dependencies:
|
|
48
48
|
version: "0"
|
49
49
|
type: :development
|
50
50
|
version_requirements: *id002
|
51
|
-
description: This gem
|
51
|
+
description: "This gem simulates named-parameters in Ruby. It's a complement to the common \n Ruby idiom of using `Hash` args to emulate the use of named parameters. \n\n It does this by extending the language with a `has_named_parameters` clause \n that allows a class to declare the parameters that are acceptable to a method.\n\n The `has_named_parameters` dictates how the presence of these parameters are\n enforced and raises an `ArgumentError` when a method invocation is made that\n violates the rules for those parameters.\n "
|
52
52
|
email: jurisgalang@gmail.com
|
53
53
|
executables: []
|
54
54
|
|