namedarguments 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 ADDED
@@ -0,0 +1,4 @@
1
+ == 0.0.1 / 2006-12-04
2
+
3
+ * 1 major enhancement
4
+ * L� breithe!
data/Manifest.txt ADDED
@@ -0,0 +1,10 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ bin/named_arguments
6
+ lib/named_arguments.rb
7
+ lib/hash_extended_tools.rb
8
+ lib/singleton_creator_mixin.rb
9
+ lib/class_settings_mixin.rb
10
+ test/test_named_arguments.rb
data/README.txt ADDED
@@ -0,0 +1,52 @@
1
+ NamedArguments
2
+ by James M. Moore
3
+
4
+ == DESCRIPTION:
5
+
6
+ Adds the ability to call class constructors with a hash of arguments to
7
+ initialize attributes in the new object.
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ class Snark
12
+ include NamedArguments
13
+
14
+ attr_accessor :color, :size, :name
15
+
16
+ attribute_defaults :color => 'blue', :size => lambda {|s| some_method_call(s)}
17
+ required_fields :color, :name
18
+ required_respond_to :name => :to_s
19
+ required_kind_of? :size => Fixnum
20
+ type_conversion :size => Fixnum
21
+ end
22
+
23
+ s = Snark.new :boojum => 7, :color => red
24
+
25
+ == INSTALL:
26
+
27
+ gem install namedarguments
28
+
29
+ == LICENSE:
30
+
31
+ (The MIT License)
32
+
33
+ Copyright (c) 2006 James M. Moore
34
+
35
+ Permission is hereby granted, free of charge, to any person obtaining
36
+ a copy of this software and associated documentation files (the
37
+ 'Software'), to deal in the Software without restriction, including
38
+ without limitation the rights to use, copy, modify, merge, publish,
39
+ distribute, sublicense, and/or sell copies of the Software, and to
40
+ permit persons to whom the Software is furnished to do so, subject to
41
+ the following conditions:
42
+
43
+ The above copyright notice and this permission notice shall be
44
+ included in all copies or substantial portions of the Software.
45
+
46
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
47
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
48
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
49
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
50
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
51
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
52
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'hoe'
3
+ require './lib/named_arguments.rb'
4
+
5
+ Hoe.new('namedarguments', NamedArguments::VERSION) do |p|
6
+ p.summary = 'Provide named arguments (hashes) to constructors to initialize attributes.'
7
+ p.author = "James M Moore"
8
+ p.email = 'james@phonesonrails.com'
9
+ p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
10
+ # p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
11
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
12
+ end
File without changes
@@ -0,0 +1,113 @@
1
+ require File.dirname(__FILE__) + '/singleton_creator_mixin'
2
+
3
+ module ClassSettingsMixin
4
+ def self.included target
5
+ target.send :extend, ClassSettingsMixinClassMethods
6
+ end
7
+ end
8
+
9
+ module ClassSettingsMixinClassMethods
10
+ include SingletonMethodCreatorMixin
11
+
12
+ # Allow you to define
13
+ # methods that set a class value hash
14
+ # and an accessor for that hash.
15
+ #
16
+ # Example:
17
+ #
18
+ # create_class_settings_method :settings
19
+ #
20
+ # creates:
21
+ #
22
+ # settings:: A class method that allows
23
+ # you to set variables
24
+ # settings?:: The current value of those variables
25
+ #
26
+ # class BlueCar
27
+ # create_class_settings_method :settings
28
+ # create_class_settings_method :has_these
29
+ #
30
+ # settings :color => :blue, :another_settting => 10
31
+ # settings :painted => true
32
+ # has_these :doors, :windows
33
+ # has_these :wheels
34
+ # end
35
+ #
36
+ # class Convertable < BlueCar
37
+ # has_these :poptop
38
+ # end
39
+ #
40
+ # BlueCar.color
41
+ # => :blue
42
+ #
43
+ # BlueCar.new.settings?
44
+ # => {:color => :blue, :painted => true, :another_settting => 10}
45
+ def create_class_settings_method name
46
+ # Build the class methods first
47
+ l = class_setting_lambda name
48
+ create_singleton_method name, l
49
+
50
+ # Allow #name? to be called as an instance method
51
+ # and default its return value to nil.
52
+ # This will be replaced on any call to the
53
+ # setter.
54
+ value_name = value_field_identifier(name)
55
+ instance_method = lambda {nil}
56
+ define_method value_name, instance_method
57
+ end
58
+
59
+ protected
60
+
61
+ # Returns a lambda that will create
62
+ # two methods:
63
+ #
64
+ # A singleton method on the current object
65
+ # that takes multiple parameters and
66
+ # stores their values. This allows
67
+ # you to define methods on the class
68
+ # that will save their parameters.
69
+ # An instance method that returns those
70
+ # saved parameters
71
+ def class_setting_lambda name #:nodoc:
72
+ value_field_id = value_field_identifier name
73
+ result = lambda do
74
+ # Note that this lambda is called
75
+ # either with a single argument
76
+ # containing a hash, or an array
77
+ # of arguments.
78
+ |*args|
79
+
80
+ if args.first.kind_of? Hash
81
+ args = args.first
82
+ end
83
+
84
+ begin
85
+ current_value = self.send value_field_id
86
+ case current_value
87
+ when Array then val = merge_arrays_of_symbols current_value, args
88
+ when Hash then val = current_value.merge args
89
+ else
90
+ raise RuntimeError.new("Attempting to merge two different kinds of data")
91
+ end
92
+ rescue NoMethodError
93
+ val = args
94
+ end
95
+
96
+ # Define the class method
97
+ create_singleton_value_method value_field_id, val
98
+
99
+ # Define the instance method
100
+ define_method value_field_id, lambda {val}
101
+ end
102
+ result
103
+ end
104
+
105
+ def value_field_identifier name #:nodoc:
106
+ return "#{name}?"
107
+ end
108
+
109
+ def merge_arrays_of_symbols a, b #:nodoc:
110
+ result = a.map(&:to_sym) + b.map(&:to_sym)
111
+ result.uniq
112
+ end
113
+ end
@@ -0,0 +1,81 @@
1
+ # Provides several hash utilities.
2
+ #
3
+ # Note that you need to extend your hash with this module:
4
+ #
5
+ # hash = {}
6
+ # hash.extend HashExtendedTools
7
+ # hash = hash.exclude :foo, :bar
8
+ #
9
+ # Or create a new class:
10
+ #
11
+ # class HashWithExtendedTools < Hash
12
+ # include HashExtendedTools
13
+ # end
14
+ module HashExtendedTools
15
+ # Change keys in a hash.
16
+ #
17
+ # Pass in a hash of:
18
+ #
19
+ # old_key => new_key
20
+ #
21
+ # Any keys matching +old_key+ will be
22
+ # deleted and a new entry created with
23
+ # the same value and the new key.
24
+ def switch_keys args = {}
25
+ args.each_pair do
26
+ |old_key, new_key|
27
+ if self.has_key?(old_key)
28
+ self[new_key] = self[old_key]
29
+ delete(old_key)
30
+ end
31
+ end
32
+ end
33
+
34
+ # Return a new hash not including
35
+ # keys that are contained in
36
+ # +keys_to_exclude+.
37
+ #
38
+ # Keys that match entries in
39
+ # +keys_to_exclude+ are deleted if
40
+ # either they match as string or a
41
+ # symbol (created with to_sym).
42
+ def exclude *keys_to_exclude
43
+ result = self.dup
44
+ keys_to_exclude.each do |k|
45
+ result.delete k.to_s
46
+ result.delete k.to_sym
47
+ end
48
+ result
49
+ end
50
+
51
+ # Given an array of keys,
52
+ # return a hash containing
53
+ # the key/value pairs
54
+ # for the matching keys.
55
+ #
56
+ # Values that are nil are not
57
+ # returned.
58
+ def slice *slice_keys
59
+ result = {}
60
+ slice_keys.each do |k|
61
+ result[k] = self[k] unless self[k].nil?
62
+ end
63
+ result
64
+ end
65
+
66
+ # Return the given attributes as a hash containing
67
+ # attribute => value pairs.
68
+ #
69
+ # obj.a = 10
70
+ # obj.b = 20
71
+ # attributes_as_hash(:a, :b)
72
+ # => {:a => 10, :b => 20}
73
+ def attributes_as_hash *attrs
74
+ result = {}
75
+ attrs.each do |a|
76
+ v = self.send a
77
+ result[a] = v unless v.nil?
78
+ end
79
+ result
80
+ end
81
+ end
@@ -0,0 +1,249 @@
1
+ require File.dirname(__FILE__) + '/class_settings_mixin'
2
+ require File.dirname(__FILE__) + '/hash_extended_tools'
3
+ require File.dirname(__FILE__) + '/singleton_creator_mixin'
4
+
5
+ # Adds the following features to a class:
6
+ #
7
+ # * Pass a hash to new and matching attributes
8
+ # will be set.
9
+ # * Set default values for arguments (attribute_defaults)
10
+ # * Require arguments (required_fields)
11
+ # * Require kind_of? tests for arguments (required_kind_of)
12
+ # * Change the type of the object passed in (type_conversion)
13
+ #
14
+ # =Sample
15
+ #
16
+ # class Snark
17
+ # include NamedArguments
18
+ #
19
+ # attr_accessor :color, :size, :name
20
+ #
21
+ # attribute_defaults :color => 'blue', :size => lambda {|s| some_method_call(s)}
22
+ # required_fields :color, :name
23
+ # required_respond_to :name => :to_s
24
+ # required_kind_of? :size => Fixnum
25
+ # type_conversion :size => Fixnum
26
+ # end
27
+ #
28
+ # = See also
29
+ #
30
+ # See NamedArgumentsClassMethods for more methods.
31
+ module NamedArguments
32
+ VERSION = '0.0.1'
33
+
34
+ include HashExtendedTools
35
+
36
+ # Requires that object.snark.kind_of? String be true
37
+ # on the call to initialize.
38
+ #
39
+ # Throws a NamedArgumentException if that test fails.
40
+ #
41
+ # required_kind_of :snark => String, :boojum => Fixnum
42
+ def required_kind_of
43
+ # Dummy for rdoc
44
+ end
45
+
46
+ # Requires that the given arguments be present on the
47
+ # call to new.
48
+ #
49
+ # required_fields [:snark, :boojum]
50
+ #
51
+ # or
52
+ #
53
+ # required_fields :snark
54
+ def required_fields
55
+ # Dummy for rdoc
56
+ end
57
+
58
+ # Requires that the given objects respond to the
59
+ # method call.
60
+ #
61
+ # required_respond_to :snark => 'hunt'
62
+ #
63
+ # Raises a NamedArgumentException on failure.
64
+ def required_respond_to
65
+ # Dummy for rdoc
66
+ end
67
+
68
+ # Set defaults for the given attributes.
69
+ #
70
+ # Values can be:
71
+ #
72
+ # * A class. The #new method is called with no arguments.
73
+ # * A Proc. The proc is called with one argument.
74
+ # * []. A new array is created.
75
+ # * {}. A new hash is created.
76
+ #
77
+ # attribute_defaults :snark => lambda {|s| String.new s.to_s}
78
+ # attribute_defaults :snark => [], :boojum => ObjectTypeFromSomewhereElse
79
+ # attribute_defaults :snark => {}
80
+ def attribute_defaults
81
+ # Dummy for rdoc
82
+ end
83
+
84
+ def self.included target # :nodoc:
85
+ target.send :include, ClassSettingsMixin
86
+ target.send :extend, NamedArgumentsClassMethods
87
+ target.send :create_class_settings_method, :required_fields
88
+ target.send :create_class_settings_method, :required_kind_of
89
+ target.send :create_class_settings_method, :required_respond_to
90
+ target.send :create_class_settings_method, :attribute_defaults
91
+ end
92
+
93
+ # Set the attributes for this object. Normally called
94
+ # by initialize.
95
+
96
+ def attributes_set(args) # :nodoc:
97
+ set_default_attributes(args)
98
+
99
+ args_plus_defaults = (attribute_defaults? || {}).merge(args)
100
+ check_required_field args_plus_defaults
101
+ check_required_kind
102
+ check_required_respond_to
103
+ end
104
+
105
+ def set_default_attributes(args) # :nodoc:
106
+ defaults = {}
107
+ (attribute_defaults? || {}).each_pair do |k, v|
108
+ if v.kind_of? Class
109
+ result = v.new
110
+ elsif v.kind_of? Proc
111
+ result = v.call self
112
+ elsif v.class == Array and v.empty?
113
+ result = Array.new
114
+ elsif v.class == Hash and v.empty?
115
+ result = Hash.new
116
+ else
117
+ result = v
118
+ end
119
+ defaults[k] = result
120
+ end
121
+ args = defaults.merge args
122
+ args.each_pair do
123
+ |k, v|
124
+ self.send("#{k}=", v)
125
+ end
126
+ end
127
+
128
+ # An array of field names. When an object is created
129
+ # all of these attributes must be passed. (They can be
130
+ # set to nil)
131
+ #
132
+ # Note that this can only be called as a class method.
133
+
134
+ # A hash of :fieldname => klass pairs that specify the
135
+ # required class of each of the attributes.
136
+
137
+ # Checks to make sure all the required fields
138
+ # are passed in.
139
+ #
140
+ # See also: required_fields
141
+
142
+ def check_required_field(fields_set) # :nodoc:
143
+ (required_fields? || []).each do
144
+ |f|
145
+ raise NamedArgumentException.new("Must set parameter: " + f.to_s) unless fields_set.has_key? f.to_sym
146
+ end
147
+ end
148
+
149
+ # Checks to make sure all the fields specifed in required_kind_of
150
+ # have the right kind of objects.
151
+ #
152
+ # See also:
153
+ # * #required_kind_of
154
+ # * #set_default_attributes
155
+
156
+ def check_required_kind # :nodoc:
157
+ (required_kind_of? || {}).each_pair do
158
+ |k, v|
159
+ raise NamedArgumentException.new("Wrong class: #{k.to_s}; should have been #{v.to_s}, object is #{self.send(k).inspect}") unless self.send(k).kind_of?(v)
160
+ end
161
+ end
162
+
163
+ def check_required_respond_to # :nodoc:
164
+ (required_respond_to? || {}).each_pair do
165
+ |k, v|
166
+ raise NamedArgumentException.new("#{k} must respond to #{v}; the object is #{self.send(k).inspect}") unless self.send(k).respond_to?(v)
167
+ end
168
+ end
169
+
170
+ # For every key/value pair in +args+, set the
171
+ # value of the attribute +key+ to +value+.
172
+ #
173
+ # class Snark
174
+ # include NamedArguments
175
+ # attr_accessor :boojum
176
+ # end
177
+ #
178
+ # s = Snark.new :boojum => 7
179
+ def initialize args = {}
180
+ if kind_of? ActiveRecord::Base
181
+ super
182
+ else
183
+ super()
184
+ end
185
+ attributes_set args
186
+ yield self if block_given?
187
+ end
188
+
189
+ def option_attr_get k # :nodoc:
190
+ option_attr_storage[k]
191
+ end
192
+
193
+ def option_attr_set k, v # :nodoc:
194
+ option_attr_storage[k] = v
195
+ end
196
+
197
+ def option_attr_storage # :nodoc:
198
+ self.options ||= {}
199
+ end
200
+
201
+ def option_attrs_keys # :nodoc:
202
+ option_attr_storage.keys
203
+ end
204
+
205
+ def option_attrs_keys_set # :nodoc:
206
+ option_attrs_keys.select do |k|
207
+ option_attr_storage.include? k
208
+ end
209
+ end
210
+ end
211
+
212
+ module NamedArgumentsClassMethods
213
+ def option_attr *array_of_names
214
+ array_of_names.each { |n|
215
+ define_method n, lambda {
216
+ option_attr_get n
217
+ }
218
+ define_method "#{n}=", lambda { |v|
219
+ option_attr_set n, v
220
+ }
221
+ }
222
+ end
223
+
224
+ def type_converter field, new_klass
225
+ alias_name = ('attribute_setter_for_' + field.to_s).to_sym
226
+ setter_method_name = (field.to_s + '=').to_sym
227
+ alias_method alias_name, setter_method_name
228
+ send :define_method, setter_method_name do |rhs|
229
+ if [Fixnum].member? new_klass
230
+ v = rhs.to_i
231
+ elsif new_klass == String
232
+ v = rhs.to_s
233
+ elsif new_klass == Symbol
234
+ v = rhs.to_sym
235
+ elsif new_klass == :boolean
236
+ v = !!rhs
237
+ elsif new_klass.kind_of? Proc
238
+ v = new_klass.call v
239
+ else
240
+ v = new_klass.new rhs
241
+ end
242
+ self.send alias_name, v
243
+ end
244
+ end
245
+ end
246
+
247
+ # Exception class thrown by NamedArguments methods.
248
+ class NamedArgumentException < Exception
249
+ end
@@ -0,0 +1,29 @@
1
+ module SingletonMethodCreatorMixin
2
+ # Create a method out of a
3
+ # name and a lambda.
4
+ #
5
+ # Example:
6
+ #
7
+ # my_lambda = lambda {13}
8
+ # create_singleton_method :return_13, my_lambda
9
+ #
10
+ # assert 13 == self.return_13
11
+ def create_singleton_method method_name, lambda_obj
12
+ sclass = class << self; self end
13
+ sclass.send(:define_method, method_name, lambda_obj)
14
+ sclass.send(:public, method_name)
15
+ end
16
+
17
+ # Create a method out of a
18
+ # value and a name
19
+ # The method will return the value.
20
+ #
21
+ # Example:
22
+ #
23
+ # create_singleton_value_method :return_14, 14
24
+ #
25
+ # assert 14 == self.return_14
26
+ def create_singleton_value_method name, value
27
+ create_singleton_method(name, lambda { value })
28
+ end
29
+ end
File without changes
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11
3
+ specification_version: 1
4
+ name: namedarguments
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.1
7
+ date: 2006-12-06 00:00:00 -08:00
8
+ summary: Provide named arguments (hashes) to constructors to initialize attributes.
9
+ require_paths:
10
+ - lib
11
+ email: james@phonesonrails.com
12
+ homepage: http://www.zenspider.com/ZSS/Products/namedarguments/
13
+ rubyforge_project: namedarguments
14
+ description: "Adds the ability to call class constructors with a hash of arguments to initialize attributes in the new object. == FEATURES/PROBLEMS: class Snark include NamedArguments attr_accessor :color, :size, :name attribute_defaults :color => 'blue', :size => lambda {|s| some_method_call(s)} required_fields :color, :name required_respond_to :name => :to_s required_kind_of? :size => Fixnum type_conversion :size => Fixnum end s = Snark.new :boojum => 7, :color => red == INSTALL:"
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ authors:
29
+ - James M Moore
30
+ files:
31
+ - History.txt
32
+ - Manifest.txt
33
+ - README.txt
34
+ - Rakefile
35
+ - bin/named_arguments
36
+ - lib/named_arguments.rb
37
+ - lib/hash_extended_tools.rb
38
+ - lib/singleton_creator_mixin.rb
39
+ - lib/class_settings_mixin.rb
40
+ - test/test_named_arguments.rb
41
+ test_files:
42
+ - test/test_named_arguments.rb
43
+ rdoc_options: []
44
+
45
+ extra_rdoc_files: []
46
+
47
+ executables:
48
+ - named_arguments
49
+ extensions: []
50
+
51
+ requirements: []
52
+
53
+ dependencies:
54
+ - !ruby/object:Gem::Dependency
55
+ name: hoe
56
+ version_requirement:
57
+ version_requirements: !ruby/object:Gem::Version::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 1.1.6
62
+ version: