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 CHANGED
@@ -1,143 +1,144 @@
1
- NamedParameters Gem
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
- See: http://en.wikipedia.org/wiki/named_parameter for more information on
6
- Named Parameters in general.
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
- Installation
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
- Usage
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
- And all your classes should be able to declare:
14
+ Get It
15
+ ------
16
+ You know you want it:
20
17
 
21
- has_named_parameters :method, :optional => [ ... ], :required => [ ... ]
18
+ gem install named-parameters
22
19
 
23
- If you want to be selective about which classes will use it, do:
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
- -- then mix-in the `NamedParameters` module into the class of your choice, for
28
- example:
30
+ Then include the `NamedParameters` module into your class:
29
31
 
30
- class FooBar
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
- Using the has_named_parameters Method
36
- -------------------------------------
37
- The `has_named_parameters` method is used to declare that a method accepts a
38
- `Hash` argument that should be treated like named-parameters:
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
- GoogleStorage.new # ArgumentError, GoogleStorage#initialize requires: access-key, secret-key
46
+ So when you invoke `your_method`, its parameter requirements will now be
47
+ enforced:
58
48
 
59
- On the other-hand, it declares that the `request` method may optionally accept
60
- a parameter named `timeout` - so the following invocations will not raise error:
61
-
62
- gs = GoogleStorage.new :'access-key' => '...', :'secret-key' => '...'
63
- gs.request '/some/path'
64
- gs.request '/some/path', :timeout => '500ms'
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
- gs.request '/some/path', :ssl => true # ArgumentError, GoogleStorage#request unrecognized parameter: ssl
57
+ has_named_parameters :send_mail, :required => :to
58
+ has_named_parameters :send_mail, :required => [ :to, :subject ]
69
59
 
70
- The `has_named_parameters` declaration may be used for either class or
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
- has_named_parameters :load, :optional => :translations
80
- def self.load filename, opts => { }
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
- Optional and Required Parameters
87
- --------------------------------
88
- Optional and required parameters may be declared in a single
89
- `has_named_parameters` declaration:
90
-
91
- has_named_parameters :request, :required => :path, :optional => :timeout
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
- To specify more than one optional or required parameter, use an `Array`:
75
+ You can also declare default values for `:required` and `:oneof` parameters,
76
+ but really, that's just silly.
94
77
 
95
- has_named_parameters :request, :required => :path, :optional => [ :timeout, :ssl ]
78
+ With `has_named_parameters`, you can mix-and-match parameter requirements:
96
79
 
97
- How It Works
98
- ------------
99
- The `has_named_parameters` declaration simply looks for the first `Hash`
100
- argument when a method that has been declared with `has_named_parameters` is
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
- It does not know the name of the `Hash` parameter for the method. So the
104
- following variations:
85
+ And is applicable to both class and instance methods:
105
86
 
106
- def service opts = { }
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
- def service options = { }
111
- # ...
112
- end
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
- def service params
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
- -- behave the same way, when the `has_named_parameter` clause is used:
113
+ So you can mix-and-match argument types in a method, and still declare that
114
+ it `has_named_parameters`:
119
115
 
120
- # the following...
121
- has_named_parameters :service, :optional => :timeout
122
- def service params
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
- # is essentially the same as...
127
- has_named_parameters :service, :optional => :timeout
128
- def service opts = { }
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
- # as well as...
133
- has_named_parameters :service, :optional => :timeout
134
- def service opts
135
- # ...
136
- end
134
+ # invocation:
135
+ request :accesskey => '0925'
137
136
 
138
- Since when the method is invoked, each one of the above could receive a `Hash`
137
+ # result isn't what's expected:
138
+ # => path: {:accesskey => '0925'}, options: {}
139
139
 
140
- service :timeout => '500ms'
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
  ------------
@@ -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 methods.
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 enables/simulates named-parameters in Ruby}
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.5
1
+ 0.0.6
@@ -1,2 +1,6 @@
1
+ require 'named-parameters/object'
1
2
  require 'named-parameters/module'
2
- require 'named-parameters/object'
3
+
4
+ # Extend object to automatically make it available for all
5
+ # user defined classes...
6
+ Object.extend NamedParameters::ClassMethods
@@ -1,5 +1,8 @@
1
- # When mixed-in, this module adds has_named_parameters class method, which
2
- # can be used to declare methods that are supposed to accepts named-parameters.
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.validate name, params, spec # :nodoc:
36
- spec[:required] ||= []
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
- spec = Hash[ spec.map{ |k, v|
40
- v = [ v ] unless v.instance_of? Array
41
- [ k, v ]
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
- sorter = lambda{ |x, y| x.to_s <=> y.to_s }
45
- allowed = (spec[:optional] + spec[:required]).sort &sorter
46
- keys = params.keys.map{ |k| k.to_sym }
47
-
48
- keys.sort! &sorter
49
- spec[:required].sort! &sorter
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
- unless spec[:required].empty?
54
- k = spec[:required] & keys
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} requires arguments for parameters: #{list[spec[:required] - k]}" \
57
- unless k == spec[:required]
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 `required` and/or `optional`
70
- # parameters will raise an `ArgumentError` if it is invoked without its
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] `method` the name of the method that is supposed to
91
+ # @param [Symbol] method the name of the method that is supposed to
79
92
  # enforce named parameters behavior.
80
93
  #
81
- # @param [Hash] `spec` the list of required and optional parameters.
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
- # @return [Hash] the specified `spec`
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
- params = args.find{ |arg| arg.instance_of? Hash }
127
- fullname = "#{owner}#{name}"
128
- NamedParameters::validate fullname, params || {}, spec
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
@@ -1,3 +1,7 @@
1
- # Extend object to automatically make it available for all
2
- # user defined classes...
3
- Object.extend NamedParameters::ClassMethods
1
+ # Do the eigenclass thingy
2
+ class Object
3
+ protected
4
+ def eigenclass # :nodoc:
5
+ class << self; self; end
6
+ end
7
+ end
@@ -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.5"
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-11}
13
- s.description = %q{This gem enables/simulates named-parameters in Ruby}
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 FooBar
5
+ class Foo
6
6
  has_named_parameters :initialize, :required => :x, :optional => [ :y, :z ]
7
- def initialize(opts = {}); end
7
+ def initialize opts = {}; end
8
8
 
9
9
  has_named_parameters :method_one, :required => :x, :optional => [ :y, :z ]
10
- def method_one(x, y, opts = {}); end
10
+ def method_one x, y, opts = {}; end
11
11
 
12
- def method_two(x, y, opts = {}); end
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
- FooBar.should respond_to :has_named_parameters
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{ FooBar.new }.should raise_error ArgumentError
22
- lambda{ FooBar.new :w => :w }.should raise_error ArgumentError
23
- lambda{ FooBar.new :x => :x }.should_not raise_error
24
- lambda{ FooBar.new :x => :x, :y => :y }.should_not raise_error
25
- lambda{ FooBar.new :x => :x, :y => :y, :z => :z }.should_not raise_error
26
- end
27
-
28
- it "should enforce named parameters for instrumented methods" do
29
- lambda{ @foobar = FooBar.new :x => :x, :y => :y, :z => :z }.should_not raise_error
30
- lambda{ @foobar.method_one :x }.should raise_error ArgumentError
31
- lambda{ @foobar.method_one :x, :y }.should raise_error ArgumentError
32
- lambda{ @foobar.method_one :x, :y, :x => :x, :y => :y, :z => :z, :w => :w }.should raise_error ArgumentError
33
- lambda{ @foobar.method_one :x => :x, :y => :y, :z => :z }.should raise_error ArgumentError
34
- lambda{ @foobar.method_one :x, :y, :w => :w }.should raise_error ArgumentError
35
- lambda{ @foobar.method_one :x, :y, :x => :x }.should_not raise_error
36
- lambda{ @foobar.method_one :x, :y, :x => :x, :y => :y }.should_not raise_error
37
- lambda{ @foobar.method_one :x, :y, :x => :x, :y => :y, :z => :z }.should_not raise_error
38
- end
39
-
40
- it "should not enforce named parameters for un-instrumented methods" do
41
- lambda{ @foobar = FooBar.new :x => :x, :y => :y, :z => :z }.should_not raise_error
42
- lambda{ @foobar.method_two :x }.should raise_error ArgumentError
43
- lambda{ @foobar.method_two :x, :y }.should_not raise_error ArgumentError
44
- lambda{ @foobar.method_two :x, :y, :w => :w }.should_not raise_error ArgumentError
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: 21
4
+ hash: 19
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 5
10
- version: 0.0.5
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-11 00:00:00 -08:00
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 enables/simulates named-parameters in Ruby
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