blockenspiel 0.2.2-java → 0.3.0-java
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/Blockenspiel.rdoc +374 -0
- data/History.rdoc +9 -0
- data/README.rdoc +26 -252
- data/Rakefile +5 -3
- data/lib/blockenspiel/impl.rb +197 -49
- data/lib/blockenspiel/version.rb +1 -1
- data/lib/blockenspiel_unmixer.jar +0 -0
- data/tests/tc_basic.rb +3 -3
- data/tests/tc_behaviors.rb +8 -8
- data/tests/tc_dsl_attrs.rb +134 -0
- data/tests/tc_dsl_methods.rb +6 -6
- data/tests/tc_dynamic.rb +55 -27
- data/tests/tc_mixins.rb +8 -8
- metadata +7 -3
data/lib/blockenspiel/impl.rb
CHANGED
@@ -81,11 +81,13 @@ module Blockenspiel
|
|
81
81
|
|
82
82
|
module DSLSetupMethods
|
83
83
|
|
84
|
+
|
85
|
+
# :stopdoc:
|
86
|
+
|
84
87
|
# Called when DSLSetupMethods extends a class.
|
85
88
|
# This sets up the current class, and adds a hook that causes
|
86
|
-
# any subclass of the current class to
|
89
|
+
# any subclass of the current class also to be set up.
|
87
90
|
|
88
|
-
# :stopdoc:
|
89
91
|
def self.extended(klass_)
|
90
92
|
unless klass_.instance_variable_defined?(:@_blockenspiel_module)
|
91
93
|
_setup_class(klass_)
|
@@ -95,6 +97,7 @@ module Blockenspiel
|
|
95
97
|
end
|
96
98
|
end
|
97
99
|
end
|
100
|
+
|
98
101
|
# :startdoc:
|
99
102
|
|
100
103
|
|
@@ -175,12 +178,7 @@ module Blockenspiel
|
|
175
178
|
end
|
176
179
|
@_blockenspiel_methods[name_] = delegate_
|
177
180
|
unless @_blockenspiel_module.public_method_defined?(name_)
|
178
|
-
@_blockenspiel_module.module_eval("
|
179
|
-
def #{name_}(*params_, &block_)
|
180
|
-
val_ = ::Blockenspiel._target_dispatch(self, :#{name_}, params_, block_)
|
181
|
-
val_ == ::Blockenspiel::TARGET_MISMATCH ? super(*params_, &block_) : val_
|
182
|
-
end
|
183
|
-
")
|
181
|
+
@_blockenspiel_module.module_eval("def #{name_}(*params_, &block_); val_ = ::Blockenspiel._target_dispatch(self, :#{name_}, params_, block_); ::Blockenspiel::NO_VALUE.equal?(val_) ? super(*params_, &block_) : val_; end\n")
|
184
182
|
end
|
185
183
|
end
|
186
184
|
|
@@ -229,6 +227,91 @@ module Blockenspiel
|
|
229
227
|
end
|
230
228
|
end
|
231
229
|
|
230
|
+
|
231
|
+
# A DSL-friendly attr_accessor.
|
232
|
+
#
|
233
|
+
# This creates the usual "name" and "name=" methods in the current
|
234
|
+
# class that can be used in the usual way. However, its implementation
|
235
|
+
# of the "name" method (the getter) also takes an optional parameter
|
236
|
+
# that causes it to behave as a setter. This is done because the usual
|
237
|
+
# setter syntax cannot be used in a parameterless block, since it is
|
238
|
+
# syntactically indistinguishable from a local variable assignment.
|
239
|
+
# The "name" method is exposed as a dsl_method.
|
240
|
+
#
|
241
|
+
# For example:
|
242
|
+
#
|
243
|
+
# dsl_attr_accessor :foo
|
244
|
+
#
|
245
|
+
# enables the following:
|
246
|
+
#
|
247
|
+
# my_block do |param|
|
248
|
+
# param.foo = 1 # Usual setter syntax works
|
249
|
+
# param.foo 2 # Alternate setter syntax also works
|
250
|
+
# puts param.foo # Usual getter syntax still works
|
251
|
+
# end
|
252
|
+
#
|
253
|
+
# my_block do
|
254
|
+
# # foo = 1 # Usual setter syntax does NOT work since it
|
255
|
+
# # looks like a local variable assignment
|
256
|
+
# foo 2 # Alternate setter syntax does work
|
257
|
+
# puts foo # Usual getter syntax still works
|
258
|
+
# end
|
259
|
+
|
260
|
+
def dsl_attr_accessor(*names_)
|
261
|
+
names_.each do |name_|
|
262
|
+
unless name_.kind_of?(::String) || name_.kind_of?(::Symbol)
|
263
|
+
raise ::TypeError, "#{name_.inspect} is not a symbol"
|
264
|
+
end
|
265
|
+
unless name_.to_s =~ /^[_a-zA-Z]\w+$/
|
266
|
+
raise ::NameError, "invalid attribute name #{name_.inspect}"
|
267
|
+
end
|
268
|
+
module_eval("def #{name_}(value_=::Blockenspiel::NO_VALUE); ::Blockenspiel::NO_VALUE.equal?(value_) ? @#{name_} : @#{name_} = value_; end\n")
|
269
|
+
alias_method("#{name_}=", name_)
|
270
|
+
dsl_method(name_)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
|
275
|
+
# A DSL-friendly attr_writer.
|
276
|
+
#
|
277
|
+
# This creates the usual "name=" method in the current class that can
|
278
|
+
# be used in the usual way. However, it also creates the method "name",
|
279
|
+
# which also functions as a setter (but not a getter). This is done
|
280
|
+
# because the usual setter syntax cannot be used in a parameterless
|
281
|
+
# block, since it is syntactically indistinguishable from a local
|
282
|
+
# variable assignment. The "name" method is exposed as a dsl_method.
|
283
|
+
#
|
284
|
+
# For example:
|
285
|
+
#
|
286
|
+
# dsl_attr_writer :foo
|
287
|
+
#
|
288
|
+
# is functionally equivalent to:
|
289
|
+
#
|
290
|
+
# attr_writer :foo
|
291
|
+
# alias_method :foo, :foo=
|
292
|
+
# dsl_method :foo
|
293
|
+
#
|
294
|
+
# which enables the following:
|
295
|
+
#
|
296
|
+
# my_block do |param|
|
297
|
+
# param.foo = 1 # Usual setter syntax works
|
298
|
+
# param.foo 2 # Alternate setter syntax also works
|
299
|
+
# end
|
300
|
+
# my_block do
|
301
|
+
# # foo = 1 # Usual setter syntax does NOT work since it
|
302
|
+
# # looks like a local variable assignment
|
303
|
+
# foo(2) # Alternate setter syntax does work
|
304
|
+
# end
|
305
|
+
|
306
|
+
def dsl_attr_writer(*names_)
|
307
|
+
names_.each do |name_|
|
308
|
+
attr_writer(name_)
|
309
|
+
alias_method(name_, "#{name_}=")
|
310
|
+
dsl_method(name_)
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
|
232
315
|
end
|
233
316
|
|
234
317
|
|
@@ -306,11 +389,7 @@ module Blockenspiel
|
|
306
389
|
|
307
390
|
def self._add_methodinfo(name_, block_, yields_)
|
308
391
|
(@_blockenspiel_methodinfo ||= ::Hash.new)[name_] = [block_, yields_]
|
309
|
-
module_eval("
|
310
|
-
def #{name_}(*params_, &block_)
|
311
|
-
self.class._invoke_methodinfo(:#{name_}, params_, block_)
|
312
|
-
end
|
313
|
-
")
|
392
|
+
module_eval("def #{name_}(*params_, &block_); self.class._invoke_methodinfo(:#{name_}, params_, block_); end\n")
|
314
393
|
end
|
315
394
|
|
316
395
|
|
@@ -324,7 +403,7 @@ module Blockenspiel
|
|
324
403
|
when :last
|
325
404
|
params_.push(block_)
|
326
405
|
end
|
327
|
-
info_[0].call(*params_)
|
406
|
+
info_[0].call(*params_, &block_)
|
328
407
|
end
|
329
408
|
|
330
409
|
end
|
@@ -348,24 +427,60 @@ module Blockenspiel
|
|
348
427
|
# === Declare a DSL method.
|
349
428
|
#
|
350
429
|
# This call creates a method that can be called from the DSL block.
|
351
|
-
# Provide a name for the method,
|
352
|
-
# implementation
|
353
|
-
#
|
354
|
-
# The <tt>:block</tt> option controls how the generated method reports
|
355
|
-
# any block provided by the caller. If set to +false+ or not given, any
|
356
|
-
# caller-provided block is ignored. If set to <tt>:first</tt>, the
|
357
|
-
# block is _prepended_ (as a +Proc+ object) to the parameters passed to
|
358
|
-
# the method's implementing block. If set to <tt>:last</tt>, the block
|
359
|
-
# is _appended_. In either case, if the caller does not provide a block,
|
360
|
-
# a value of +nil+ is pre- or appended to the parameter list. A value of
|
361
|
-
# +true+ is equivalent to <tt>:first</tt>.
|
362
|
-
# (This is a workaround for the fact that blocks cannot themselves take
|
363
|
-
# block parameters in Ruby 1.8.)
|
430
|
+
# Provide a name for the method, a block defining the method's
|
431
|
+
# implementation, and an optional hash of options.
|
364
432
|
#
|
433
|
+
# By default, a method of the same name is also made available to
|
434
|
+
# parameterless blocks. To change the name of the parameterless method,
|
435
|
+
# provide its name as the value of the <tt>:dsl_method</tt> option.
|
436
|
+
# To disable this method for parameterless blocks, set the
|
437
|
+
# <tt>:dsl_method</tt> option to +false+.
|
438
|
+
#
|
439
|
+
# The <tt>:mixin</tt> option is a deprecated alias for
|
440
|
+
# <tt>:dsl_method</tt>.
|
441
|
+
#
|
442
|
+
# === Warning about the +return+ keyword
|
443
|
+
#
|
444
|
+
# Because you are implementing your method using a block, remember the
|
445
|
+
# distinction between <tt>Proc.new</tt> and +lambda+. Invoking +return+
|
446
|
+
# from the former does not return from the block, but returns from the
|
447
|
+
# surrounding method scope. Since normal blocks passed to methods are
|
448
|
+
# of the former type, be very careful about using the +return+ keyword:
|
449
|
+
#
|
450
|
+
# add_method(:foo) do |param|
|
451
|
+
# puts "foo called with parameter "+param.inspect
|
452
|
+
# return "a return value" # DOESN'T WORK LIKE YOU EXPECT!
|
453
|
+
# end
|
454
|
+
#
|
455
|
+
# To return a value from the method you are creating, set the evaluation
|
456
|
+
# value at the end of the block:
|
457
|
+
#
|
458
|
+
# add_method(:foo) do |param|
|
459
|
+
# puts "foo called with parameter "+param.inspect
|
460
|
+
# "a return value" # Returns from method foo
|
461
|
+
# end
|
462
|
+
#
|
463
|
+
# If you must use the +return+ keyword, create your block as a lambda
|
464
|
+
# as in this example:
|
465
|
+
#
|
466
|
+
# code = lambda do |param|
|
467
|
+
# puts "foo called with parameter "+param.inspect
|
468
|
+
# return "a return value" # Returns from method foo
|
469
|
+
# end
|
470
|
+
# add_method(:foo, &code)
|
471
|
+
#
|
472
|
+
# === Accepting a block argument
|
473
|
+
#
|
474
|
+
# If you want your method to take a block, you have several options
|
475
|
+
# depending on your Ruby version. If you are running the standard Matz
|
476
|
+
# Ruby interpreter (MRI) version 1.8.7 or later (including 1.9.x), you
|
477
|
+
# can use the standard "&" block argument notation to receive the block.
|
478
|
+
# Note that you must call the passed block using the +call+ method since
|
479
|
+
# Ruby doesn't support invoking such a block with +yield+.
|
365
480
|
# For example, to create a method named "foo" that takes one parameter
|
366
481
|
# and a block, do this:
|
367
482
|
#
|
368
|
-
# add_method(:foo
|
483
|
+
# add_method(:foo) do |param, &block|
|
369
484
|
# puts "foo called with parameter "+param.inspect
|
370
485
|
# puts "the block returned "+block.call.inspect
|
371
486
|
# end
|
@@ -374,18 +489,32 @@ module Blockenspiel
|
|
374
489
|
#
|
375
490
|
# foo("hello"){ "a value" }
|
376
491
|
#
|
377
|
-
#
|
378
|
-
#
|
379
|
-
#
|
380
|
-
#
|
381
|
-
#
|
492
|
+
# If you are using MRI 1.8.6, however, the parser does not support
|
493
|
+
# passing a block argument to a block. Oddly, the current version of
|
494
|
+
# JRuby (version 1.4.0 as of this writing) also does not support this
|
495
|
+
# syntax, though it claims MRI 1.8.7 compatibility. (See bug JRUBY-4180
|
496
|
+
# to track this issue.) If your Ruby interpreter doesn't support the
|
497
|
+
# standard way to create a method that takes a block, Blockenspiel
|
498
|
+
# provides an alternative in the form of the <tt>:block</tt> option.
|
499
|
+
# This option causes blocks provided by the caller to be included in
|
500
|
+
# the normal parameter list to your method, instead of as a block
|
501
|
+
# parameter. It can be set to <tt>:first</tt> or <tt>:last</tt> to
|
502
|
+
# prepend or append, respectively, the block (as a +Proc+ object) to
|
503
|
+
# the parameter list. If the caller does not include a block when
|
504
|
+
# calling your DSL method, nil is prepended/appended. For example:
|
382
505
|
#
|
383
|
-
#
|
384
|
-
#
|
506
|
+
# add_method(:foo, :block => :last) do |param, block|
|
507
|
+
# puts "foo called with parameter "+param.inspect
|
508
|
+
# if block
|
509
|
+
# puts "the block returned "+block.call.inspect
|
510
|
+
# else
|
511
|
+
# puts "no block passed"
|
512
|
+
# end
|
513
|
+
# end
|
385
514
|
#
|
386
|
-
# The <tt>:receive_block</tt> option is
|
387
|
-
#
|
388
|
-
#
|
515
|
+
# The <tt>:receive_block</tt> option is a deprecated alternative.
|
516
|
+
# Setting <tt>:receive_block => true</tt> is currently equivalent to
|
517
|
+
# setting <tt>:block => :last</tt>.
|
389
518
|
|
390
519
|
def add_method(name_, opts_={}, &block_)
|
391
520
|
receive_block_ = opts_[:receive_block] ? :last : opts_[:block]
|
@@ -402,7 +531,7 @@ module Blockenspiel
|
|
402
531
|
|
403
532
|
|
404
533
|
# :stopdoc:
|
405
|
-
|
534
|
+
NO_VALUE = ::Object.new
|
406
535
|
# :startdoc:
|
407
536
|
|
408
537
|
@_target_stacks = ::Hash.new
|
@@ -411,18 +540,37 @@ module Blockenspiel
|
|
411
540
|
@_mutex = ::Mutex.new
|
412
541
|
|
413
542
|
|
414
|
-
# === Invoke a given block
|
543
|
+
# === Invoke a given block
|
415
544
|
#
|
416
545
|
# This is the meat of Blockenspiel. Call this function to invoke a block
|
417
546
|
# provided by the user of your API.
|
418
547
|
#
|
548
|
+
# For example, if you want users of your API to be able to do this:
|
549
|
+
#
|
550
|
+
# call_dsl do
|
551
|
+
# foo(1)
|
552
|
+
# bar(2)
|
553
|
+
# end
|
554
|
+
#
|
555
|
+
# Then you should implement <tt>call_dsl</tt> like this:
|
556
|
+
#
|
557
|
+
# def call_dsl(&block)
|
558
|
+
# my_dsl = create_block_implementation
|
559
|
+
# Blockenspiel.invoke(block, my_dsl)
|
560
|
+
# do_something_with(my_dsl)
|
561
|
+
# end
|
562
|
+
#
|
563
|
+
# In the above, <tt>create_block_implementation</tt> is a placeholder that
|
564
|
+
# returns an instance of your DSL methods class. This class includes the
|
565
|
+
# Blockenspiel::DSL module and defines the DSL methods +foo+ and +bar+.
|
566
|
+
#
|
419
567
|
# Normally, this method will check the block's arity to see whether it
|
420
568
|
# takes a parameter. If so, it will pass the given target to the block.
|
421
569
|
# If the block takes no parameter, and the given target is an instance of
|
422
570
|
# a class with DSL capability, the DSL methods are made available on the
|
423
571
|
# caller's self object so they may be called without a block parameter.
|
424
572
|
#
|
425
|
-
# Recognized options
|
573
|
+
# === Recognized options
|
426
574
|
#
|
427
575
|
# <tt>:parameterless</tt>::
|
428
576
|
# If set to false, disables parameterless blocks and always attempts to
|
@@ -471,7 +619,7 @@ module Blockenspiel
|
|
471
619
|
# add_method(:set_foo) do |value|
|
472
620
|
# my_foo = value
|
473
621
|
# end
|
474
|
-
# add_method(:set_things_from_block
|
622
|
+
# add_method(:set_things_from_block) do |value, &blk|
|
475
623
|
# my_foo = value
|
476
624
|
# my_bar = blk.call
|
477
625
|
# end
|
@@ -495,10 +643,10 @@ module Blockenspiel
|
|
495
643
|
#
|
496
644
|
# The obvious advantage of using dynamic object generation is that you are
|
497
645
|
# creating methods using closures, which provides the opportunity to, for
|
498
|
-
# example, modify closure variables such as my_foo. This is more
|
499
|
-
# to do when you create a target class since its methods do not
|
500
|
-
# to outside data. Hence, in the above example, we hand-waved,
|
501
|
-
# existence of some method called "set_my_foo_from".
|
646
|
+
# example, modify closure local variables such as my_foo. This is more
|
647
|
+
# difficult to do when you create a target class since its methods do not
|
648
|
+
# have access to outside data. Hence, in the above example, we hand-waved,
|
649
|
+
# assuming the existence of some method called "set_my_foo_from".
|
502
650
|
#
|
503
651
|
# The disadvantage is performance. If you dynamically generate a target
|
504
652
|
# object, it involves parsing and creating a new class whenever it is
|
@@ -643,11 +791,11 @@ module Blockenspiel
|
|
643
791
|
# This implements the mapping between DSL module methods and target object methods.
|
644
792
|
# We look up the current target object based on the current thread.
|
645
793
|
# Then we attempt to call the given method on that object.
|
646
|
-
# If we can't find an appropriate method to call, return the special value
|
794
|
+
# If we can't find an appropriate method to call, return the special value NO_VALUE.
|
647
795
|
|
648
796
|
def self._target_dispatch(object_, name_, params_, block_) # :nodoc:
|
649
797
|
target_stack_ = @_target_stacks[[::Thread.current.object_id, object_.object_id]]
|
650
|
-
return ::Blockenspiel::
|
798
|
+
return ::Blockenspiel::NO_VALUE unless target_stack_
|
651
799
|
target_stack_.reverse_each do |target_|
|
652
800
|
target_class_ = target_.class
|
653
801
|
delegate_ = target_class_._get_blockenspiel_delegate(name_)
|
@@ -655,7 +803,7 @@ module Blockenspiel
|
|
655
803
|
return target_.send(delegate_, *params_, &block_)
|
656
804
|
end
|
657
805
|
end
|
658
|
-
return ::Blockenspiel::
|
806
|
+
return ::Blockenspiel::NO_VALUE
|
659
807
|
end
|
660
808
|
|
661
809
|
|
data/lib/blockenspiel/version.rb
CHANGED
Binary file
|
data/tests/tc_basic.rb
CHANGED
@@ -74,7 +74,7 @@ module Blockenspiel
|
|
74
74
|
# * Asserts that the specified target object does in fact receive the block messages.
|
75
75
|
|
76
76
|
def test_basic_param
|
77
|
-
block_ =
|
77
|
+
block_ = ::Proc.new do |t_|
|
78
78
|
t_.set_value(:a, 1)
|
79
79
|
t_.set_value_by_block(:b){ 2 }
|
80
80
|
assert(!self.respond_to?(:set_value))
|
@@ -94,7 +94,7 @@ module Blockenspiel
|
|
94
94
|
# * Asserts that the specified target object still receives the messages.
|
95
95
|
|
96
96
|
def test_basic_mixin
|
97
|
-
block_ =
|
97
|
+
block_ = ::Proc.new do
|
98
98
|
set_value(:a, 1)
|
99
99
|
set_value_by_block(:b){ 2 }
|
100
100
|
end
|
@@ -113,7 +113,7 @@ module Blockenspiel
|
|
113
113
|
# * Asserts that receivers with blocks are handled properly.
|
114
114
|
|
115
115
|
def test_basic_builder
|
116
|
-
block_ =
|
116
|
+
block_ = ::Proc.new do
|
117
117
|
set_value(:a, 1)
|
118
118
|
set_value_by_block(:b){ 2 }
|
119
119
|
end
|
data/tests/tc_behaviors.rb
CHANGED
@@ -89,7 +89,7 @@ module Blockenspiel
|
|
89
89
|
hash_ = ::Hash.new
|
90
90
|
context_self_ = self
|
91
91
|
@my_instance_variable_test = :hello
|
92
|
-
block_ =
|
92
|
+
block_ = ::Proc.new do
|
93
93
|
set_value1('a', 1)
|
94
94
|
set_value2('b'){ 2 }
|
95
95
|
set_value3('c', 3)
|
@@ -116,7 +116,7 @@ module Blockenspiel
|
|
116
116
|
hash_ = ::Hash.new
|
117
117
|
context_self_ = self
|
118
118
|
@my_instance_variable_test = :hello
|
119
|
-
block_ =
|
119
|
+
block_ = ::Proc.new do
|
120
120
|
set_value1('a', 1)
|
121
121
|
set_value2('b'){ 2 }
|
122
122
|
set_value3_dslversion('c', 3)
|
@@ -140,13 +140,13 @@ module Blockenspiel
|
|
140
140
|
|
141
141
|
def test_disable_parameterless
|
142
142
|
hash_ = ::Hash.new
|
143
|
-
block1_ =
|
143
|
+
block1_ = ::Proc.new do ||
|
144
144
|
set_value1('a', 1)
|
145
145
|
end
|
146
|
-
block2_ =
|
146
|
+
block2_ = ::Proc.new do |target_|
|
147
147
|
target_.set_value1('b', 2)
|
148
148
|
end
|
149
|
-
block3_ =
|
149
|
+
block3_ = ::Proc.new do
|
150
150
|
set_value1('c', 3)
|
151
151
|
end
|
152
152
|
assert_raise(::Blockenspiel::BlockParameterError) do
|
@@ -167,13 +167,13 @@ module Blockenspiel
|
|
167
167
|
|
168
168
|
def test_disable_parametered
|
169
169
|
hash_ = ::Hash.new
|
170
|
-
block1_ =
|
170
|
+
block1_ = ::Proc.new do ||
|
171
171
|
set_value1('a', 1)
|
172
172
|
end
|
173
|
-
block2_ =
|
173
|
+
block2_ = ::Proc.new do |target_|
|
174
174
|
target_.set_value1('b', 2)
|
175
175
|
end
|
176
|
-
block3_ =
|
176
|
+
block3_ = ::Proc.new do
|
177
177
|
set_value1('c', 3)
|
178
178
|
end
|
179
179
|
::Blockenspiel.invoke(block1_, Target1.new(hash_), :parameter => false)
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Blockenspiel dsl attribute tests
|
4
|
+
#
|
5
|
+
# This file contains tests for the dsl attribute directives.
|
6
|
+
#
|
7
|
+
# -----------------------------------------------------------------------------
|
8
|
+
# Copyright 2008-2009 Daniel Azuma
|
9
|
+
#
|
10
|
+
# All rights reserved.
|
11
|
+
#
|
12
|
+
# Redistribution and use in source and binary forms, with or without
|
13
|
+
# modification, are permitted provided that the following conditions are met:
|
14
|
+
#
|
15
|
+
# * Redistributions of source code must retain the above copyright notice,
|
16
|
+
# this list of conditions and the following disclaimer.
|
17
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
18
|
+
# this list of conditions and the following disclaimer in the documentation
|
19
|
+
# and/or other materials provided with the distribution.
|
20
|
+
# * Neither the name of the copyright holder, nor the names of any other
|
21
|
+
# contributors to this software, may be used to endorse or promote products
|
22
|
+
# derived from this software without specific prior written permission.
|
23
|
+
#
|
24
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
25
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
26
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
27
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
28
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
29
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
30
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
31
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
32
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
33
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
34
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
35
|
+
# -----------------------------------------------------------------------------
|
36
|
+
;
|
37
|
+
|
38
|
+
|
39
|
+
require 'test/unit'
|
40
|
+
require ::File.expand_path("#{::File.dirname(__FILE__)}/../lib/blockenspiel.rb")
|
41
|
+
|
42
|
+
|
43
|
+
module Blockenspiel
|
44
|
+
module Tests # :nodoc:
|
45
|
+
|
46
|
+
class TestDSLAttrs < ::Test::Unit::TestCase # :nodoc:
|
47
|
+
|
48
|
+
|
49
|
+
class WriterTarget < ::Blockenspiel::Base
|
50
|
+
|
51
|
+
dsl_attr_writer(:attr1, :attr2)
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
class AccessorTarget < ::Blockenspiel::Base
|
57
|
+
|
58
|
+
dsl_attr_accessor(:attr1, :attr2)
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
# Test dsl attr writer in a parametered block
|
64
|
+
#
|
65
|
+
# * Asserts that the standard setter syntax works
|
66
|
+
# * Asserts that the alternate setter syntax works
|
67
|
+
|
68
|
+
def test_writer_parametered
|
69
|
+
block_ = ::Proc.new do |param_|
|
70
|
+
param_.attr1 = 1
|
71
|
+
assert_equal(2, param_.attr2(2))
|
72
|
+
end
|
73
|
+
target_ = WriterTarget.new
|
74
|
+
::Blockenspiel.invoke(block_, target_)
|
75
|
+
assert_equal(1, target_.instance_variable_get(:@attr1))
|
76
|
+
assert_equal(2, target_.instance_variable_get(:@attr2))
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
# Test dsl attr writer in a parameterless block
|
81
|
+
#
|
82
|
+
# * Asserts that the alternate setter syntax works
|
83
|
+
|
84
|
+
def test_writer_parameterless
|
85
|
+
block_ = ::Proc.new do
|
86
|
+
assert_equal(2, attr2(2))
|
87
|
+
end
|
88
|
+
target_ = WriterTarget.new
|
89
|
+
::Blockenspiel.invoke(block_, target_)
|
90
|
+
assert_nil(target_.instance_variable_get(:@attr1))
|
91
|
+
assert_equal(2, target_.instance_variable_get(:@attr2))
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
# Test dsl attr accessor in a parametered block
|
96
|
+
#
|
97
|
+
# * Asserts that the standard setter syntax works
|
98
|
+
# * Asserts that the alternate setter syntax works
|
99
|
+
# * Asserts that the getter syntax works
|
100
|
+
|
101
|
+
def _test_accessor_parametered
|
102
|
+
block_ = ::Proc.new do |param_|
|
103
|
+
param_.attr1 = 1
|
104
|
+
assert_equal(2, param_.attr2(2))
|
105
|
+
assert_equal(2, param_.attr2)
|
106
|
+
end
|
107
|
+
target_ = AccessorTarget.new
|
108
|
+
::Blockenspiel.invoke(block_, target_)
|
109
|
+
assert_equal(1, target_.instance_variable_get(:@attr1))
|
110
|
+
assert_equal(2, target_.instance_variable_get(:@attr2))
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
# Test dsl attr accessor in a parameterless block
|
115
|
+
#
|
116
|
+
# * Asserts that the alternate setter syntax works
|
117
|
+
# * Asserts that the getter syntax works
|
118
|
+
|
119
|
+
def test_accessor_parameterless
|
120
|
+
block_ = ::Proc.new do
|
121
|
+
assert_equal(2, attr2(2))
|
122
|
+
assert_equal(2, attr2)
|
123
|
+
end
|
124
|
+
target_ = AccessorTarget.new
|
125
|
+
::Blockenspiel.invoke(block_, target_)
|
126
|
+
assert_nil(target_.instance_variable_get(:@attr1))
|
127
|
+
assert_equal(2, target_.instance_variable_get(:@attr2))
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
end
|
data/tests/tc_dsl_methods.rb
CHANGED
@@ -203,7 +203,7 @@ module Blockenspiel
|
|
203
203
|
|
204
204
|
def test_default_setting
|
205
205
|
hash_ = ::Hash.new
|
206
|
-
block_ =
|
206
|
+
block_ = ::Proc.new do
|
207
207
|
set_value1('a', 1)
|
208
208
|
set_value2('b'){ 2 }
|
209
209
|
assert_raise(::NoMethodError){ _set_value3('c', 3) }
|
@@ -223,7 +223,7 @@ module Blockenspiel
|
|
223
223
|
|
224
224
|
def test_onoff_switching
|
225
225
|
hash_ = ::Hash.new
|
226
|
-
block_ =
|
226
|
+
block_ = ::Proc.new do
|
227
227
|
assert_raise(::NoMethodError){ _set_value1('a', 1) }
|
228
228
|
set_value2('b'){ 2 }
|
229
229
|
_set_value3('c', 3)
|
@@ -242,7 +242,7 @@ module Blockenspiel
|
|
242
242
|
|
243
243
|
def test_explicit_add
|
244
244
|
hash_ = ::Hash.new
|
245
|
-
block_ =
|
245
|
+
block_ = ::Proc.new do
|
246
246
|
set_value1('a', 1)
|
247
247
|
assert_raise(::NoMethodError){ set_value2('b'){ 2 } }
|
248
248
|
renamed_set_value2('c'){ 3 }
|
@@ -263,7 +263,7 @@ module Blockenspiel
|
|
263
263
|
|
264
264
|
def test_explicit_removing
|
265
265
|
hash_ = ::Hash.new
|
266
|
-
block_ =
|
266
|
+
block_ = ::Proc.new do
|
267
267
|
assert_raise(::NoMethodError){ set_value1('a', 1) }
|
268
268
|
assert_raise(::NoMethodError){ set_value2('b'){ 2 } }
|
269
269
|
renamed_set_value2('c'){ 3 }
|
@@ -282,7 +282,7 @@ module Blockenspiel
|
|
282
282
|
|
283
283
|
def test_subclassing
|
284
284
|
hash_ = ::Hash.new
|
285
|
-
block_ =
|
285
|
+
block_ = ::Proc.new do
|
286
286
|
set_value1('a', 1)
|
287
287
|
set_value2('b'){ 2 }
|
288
288
|
assert_raise(::NoMethodError){ set_value3('c', 3) }
|
@@ -307,7 +307,7 @@ module Blockenspiel
|
|
307
307
|
|
308
308
|
def test_multiple_dsl_methods
|
309
309
|
hash_ = ::Hash.new
|
310
|
-
block_ =
|
310
|
+
block_ = ::Proc.new do
|
311
311
|
set_value1('a', 1)
|
312
312
|
renamed_set_value2('b'){ 2 }
|
313
313
|
assert_raise(::NoMethodError){ set_value2('c', 3) }
|