dslkit 0.2.0
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/CHANGES +2 -0
- data/GPL +340 -0
- data/Rakefile +83 -0
- data/TODO +0 -0
- data/VERSION +1 -0
- data/examples/mail.rb +76 -0
- data/examples/mm.rb +148 -0
- data/examples/multiply.reg +42 -0
- data/examples/null_pattern.rb +52 -0
- data/examples/recipe.rb +81 -0
- data/examples/recipe2.rb +82 -0
- data/examples/recipe_common.rb +99 -0
- data/examples/subtract.reg +9 -0
- data/install.rb +17 -0
- data/lib/dslkit/polite.rb +538 -0
- data/lib/dslkit/rude.rb +23 -0
- data/lib/dslkit.rb +2 -0
- data/tests/runner.rb +12 -0
- data/tests/test_common.rb +180 -0
- data/tests/test_polite.rb +91 -0
- data/tests/test_rude.rb +70 -0
- metadata +69 -0
@@ -0,0 +1,538 @@
|
|
1
|
+
# = dslkit - Building Blocks for Domain Specific Languages (DSL)
|
2
|
+
#
|
3
|
+
# == Description
|
4
|
+
#
|
5
|
+
# This library contains recurring patterns, that are useful in the creation of
|
6
|
+
# internal Domain Specific Languages (DSL) in Ruby.
|
7
|
+
#
|
8
|
+
# == Author
|
9
|
+
#
|
10
|
+
# Florian Frank <mailto:flori@ping.de>
|
11
|
+
#
|
12
|
+
# == License
|
13
|
+
#
|
14
|
+
# This is free software; you can redistribute it and/or modify it under the
|
15
|
+
# terms of the GNU General Public License Version 2 as published by the Free
|
16
|
+
# Software Foundation: www.gnu.org/copyleft/gpl.html
|
17
|
+
#
|
18
|
+
# == Download
|
19
|
+
#
|
20
|
+
# The latest version of this library can be downloaded at
|
21
|
+
#
|
22
|
+
# * http://rubyforge.org/frs?group_id=2248
|
23
|
+
#
|
24
|
+
# Online Documentation should be located at
|
25
|
+
#
|
26
|
+
# * http://dslkit.rubyforge.org
|
27
|
+
#
|
28
|
+
# == Examples
|
29
|
+
#
|
30
|
+
# Some nice examples on how to use dslkit are located in the examples/
|
31
|
+
# subdirectory of this library.
|
32
|
+
#
|
33
|
+
module DSLKit
|
34
|
+
# This module contains some handy methods to deal with eigenclasses. Those
|
35
|
+
# are also known as virtual classes, singleton classes, metaclasses, plus all
|
36
|
+
# the other names Matz doesn't like enough to actually accept one of the
|
37
|
+
# names.
|
38
|
+
#
|
39
|
+
# The module can be included into other modules/classes to make the methods available.
|
40
|
+
module Eigenclass
|
41
|
+
# Returns the eigenclass of this object.
|
42
|
+
def eigenclass
|
43
|
+
class << self; self; end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Evaluates the _block_ in context of the eigenclass of this object.
|
47
|
+
def eigenclass_eval(&block)
|
48
|
+
eigenclass.instance_eval(&block)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
module ClassMethod
|
53
|
+
include Eigenclass
|
54
|
+
|
55
|
+
# Define a class method named _name_ using _block_. To be able to take
|
56
|
+
# blocks as arguments in the given _block_ Ruby 1.9 is required.
|
57
|
+
def class_define_method(name, &block)
|
58
|
+
eigenclass_eval { define_method(name, &block) }
|
59
|
+
end
|
60
|
+
|
61
|
+
# Define reader and writer attribute methods for all <i>*ids</i>.
|
62
|
+
def class_attr_accessor(*ids)
|
63
|
+
eigenclass_eval { attr_accessor(*ids) }
|
64
|
+
end
|
65
|
+
|
66
|
+
# Define reader attribute methods for all <i>*ids</i>.
|
67
|
+
def class_attr_reader(*ids)
|
68
|
+
eigenclass_eval { attr_reader(*ids) }
|
69
|
+
end
|
70
|
+
|
71
|
+
# Define writer attribute methods for all <i>*ids</i>.
|
72
|
+
def class_attr_writer(*ids)
|
73
|
+
eigenclass_eval { attr_writer(*ids) }
|
74
|
+
end
|
75
|
+
|
76
|
+
# I boycott attr!
|
77
|
+
end
|
78
|
+
|
79
|
+
module ThreadLocal
|
80
|
+
# Define a thread local variable named _name_ in this module/class. If the
|
81
|
+
# value _value_ is given, it is used to initialize the variable.
|
82
|
+
def thread_local(name, value = nil)
|
83
|
+
is_a?(Module) or raise TypeError, "receiver has to be a Module"
|
84
|
+
|
85
|
+
name = name.to_s
|
86
|
+
my_id = "__thread_local_#{__id__}__"
|
87
|
+
|
88
|
+
cleanup = eval <<-'EOT', TOPLEVEL_BINDING
|
89
|
+
lambda do |my_object_id|
|
90
|
+
my_id = "__thread_local_#{my_object_id}__"
|
91
|
+
begin
|
92
|
+
old = Thread.critical
|
93
|
+
Thread.critical = true
|
94
|
+
for t in Thread.list
|
95
|
+
t[my_id] = nil if t[my_id]
|
96
|
+
end
|
97
|
+
ensure
|
98
|
+
Thread.critical = old
|
99
|
+
end
|
100
|
+
end
|
101
|
+
EOT
|
102
|
+
ObjectSpace.define_finalizer(self, cleanup)
|
103
|
+
|
104
|
+
define_method(name) do
|
105
|
+
Thread.current[my_id] ||= {}
|
106
|
+
Thread.current[my_id][name]
|
107
|
+
end
|
108
|
+
|
109
|
+
define_method("#{name}=") do |value|
|
110
|
+
Thread.current[my_id] ||= {}
|
111
|
+
Thread.current[my_id][name] = value
|
112
|
+
end
|
113
|
+
|
114
|
+
if value
|
115
|
+
Thread.current[my_id] = {}
|
116
|
+
Thread.current[my_id][name] = value
|
117
|
+
end
|
118
|
+
self
|
119
|
+
end
|
120
|
+
|
121
|
+
# Define a thread local variable for the current instance with name _name_.
|
122
|
+
# If the value _value_ is given, it is used to initialize the variable.
|
123
|
+
def instance_thread_local(name, value = nil)
|
124
|
+
sc = class << self
|
125
|
+
extend DSLKit::ThreadLocal
|
126
|
+
self
|
127
|
+
end
|
128
|
+
sc.thread_local name, value
|
129
|
+
self
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
module ThreadGlobal
|
134
|
+
# Define a thread global variable named _name_ in this module/class. If the
|
135
|
+
# value _value_ is given, it is used to initialize the variable.
|
136
|
+
def thread_global(name, value = nil)
|
137
|
+
is_a?(Module) or raise TypeError, "receiver has to be a Module"
|
138
|
+
|
139
|
+
require 'thread'
|
140
|
+
name = name.to_s
|
141
|
+
var_name = "@__#{name}_#{__id__.abs}__"
|
142
|
+
|
143
|
+
lock = Mutex.new
|
144
|
+
modul = self
|
145
|
+
|
146
|
+
define_method(name) do
|
147
|
+
lock.synchronize { modul.instance_variable_get var_name }
|
148
|
+
end
|
149
|
+
|
150
|
+
define_method(name + "=") do |value|
|
151
|
+
lock.synchronize { modul.instance_variable_set var_name, value }
|
152
|
+
end
|
153
|
+
|
154
|
+
modul.instance_variable_set var_name, value if value
|
155
|
+
self
|
156
|
+
end
|
157
|
+
|
158
|
+
# Define a thread global variable for the current instance with name
|
159
|
+
# _name_. If the value _value_ is given, it is used to initialize the
|
160
|
+
# variable.
|
161
|
+
def instance_thread_global(name, value = nil)
|
162
|
+
sc = class << self
|
163
|
+
extend DSLKit::ThreadGlobal
|
164
|
+
self
|
165
|
+
end
|
166
|
+
sc.thread_global name, value
|
167
|
+
self
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
module InstanceExec
|
172
|
+
class << self
|
173
|
+
attr_accessor :pool
|
174
|
+
attr_accessor :count
|
175
|
+
end
|
176
|
+
self.count = 0
|
177
|
+
self.pool = []
|
178
|
+
|
179
|
+
# This is a pure ruby implementation of Ruby 1.9's instance_exec method. It
|
180
|
+
# executes _block_ in the context of this object while parsing <i>*args</i> into
|
181
|
+
# the block.
|
182
|
+
def instance_exec(*args, &block)
|
183
|
+
instance = self
|
184
|
+
id = instance_exec_fetch_symbol
|
185
|
+
InstanceExec.module_eval do
|
186
|
+
begin
|
187
|
+
define_method id, block
|
188
|
+
instance.__send__ id, *args
|
189
|
+
ensure
|
190
|
+
remove_method id if method_defined?(id)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
ensure
|
194
|
+
InstanceExec.pool << id
|
195
|
+
end
|
196
|
+
|
197
|
+
private
|
198
|
+
|
199
|
+
# Fetch a symbol from a pool in thread save way. If no more symbols are
|
200
|
+
# available create a new one, that will be pushed into the pool later.
|
201
|
+
def instance_exec_fetch_symbol
|
202
|
+
old = Thread.critical
|
203
|
+
Thread.critical = true
|
204
|
+
if InstanceExec.pool.empty?
|
205
|
+
InstanceExec.count += 1
|
206
|
+
symbol = :"__instance_exec_#{InstanceExec.count}__"
|
207
|
+
else
|
208
|
+
symbol = InstanceExec.pool.shift
|
209
|
+
end
|
210
|
+
return symbol
|
211
|
+
ensure
|
212
|
+
Thread.critical = old
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
module Interpreter
|
217
|
+
include InstanceExec
|
218
|
+
|
219
|
+
# Interpret the string _source_ as a body of a block, while passing
|
220
|
+
# <i>*args</i> into the block.
|
221
|
+
#
|
222
|
+
# A small example explains how the method is supposed to be used and how
|
223
|
+
# the <i>*args</i> can be fetched:
|
224
|
+
#
|
225
|
+
# class A
|
226
|
+
# include DSLKit::Interpreter
|
227
|
+
# def c
|
228
|
+
# 3
|
229
|
+
# end
|
230
|
+
# end
|
231
|
+
#
|
232
|
+
# A.new.interpret('|a,b| a + b + c', 1, 2) # => 6
|
233
|
+
#
|
234
|
+
# To use a specified binding see #interpret_with_binding.
|
235
|
+
def interpret(source, *args)
|
236
|
+
interpret_with_binding(source, binding, *args)
|
237
|
+
end
|
238
|
+
|
239
|
+
# Interpret the string _source_ as a body of a block, while passing
|
240
|
+
# <i>*args</i> into the block and using _my_binding_ for evaluation.
|
241
|
+
#
|
242
|
+
# A small example:
|
243
|
+
#
|
244
|
+
# class A
|
245
|
+
# include DSLKit::Interpreter
|
246
|
+
# def c
|
247
|
+
# 3
|
248
|
+
# end
|
249
|
+
# def foo
|
250
|
+
# b = 2
|
251
|
+
# interpret_with_binding('|a| a + b + c', binding, 1) # => 6
|
252
|
+
# end
|
253
|
+
# end
|
254
|
+
# A.new.foo # => 6
|
255
|
+
#
|
256
|
+
# See also #interpret.
|
257
|
+
def interpret_with_binding(source, my_binding, *args)
|
258
|
+
path = '(interpret)'
|
259
|
+
if source.respond_to? :to_io
|
260
|
+
path = source.path if source.respond_to? :path
|
261
|
+
source = source.to_io.read
|
262
|
+
end
|
263
|
+
block = lambda { |*a| eval("lambda { #{source} }", my_binding, path).call(*a) }
|
264
|
+
instance_exec(*args, &block)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
# This module contains the _constant_ method. For small example of its usage
|
269
|
+
# see the documentation of the DSLAccessor module.
|
270
|
+
module Constant
|
271
|
+
# Create a constant named _name_, that refers to value _value_. _value is
|
272
|
+
# frozen, if this is possible. If you want to modify/exchange a value use
|
273
|
+
# DSLAccessor#dsl_reader/DSLAccessor#dsl_accessor instead.
|
274
|
+
def constant(name, value)
|
275
|
+
value = value.freeze rescue value
|
276
|
+
define_method(name) { value }
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
# The DSLAccessor module contains some methods, that can be used to make
|
281
|
+
# simple accessors for a DSL.
|
282
|
+
#
|
283
|
+
#
|
284
|
+
# class CoffeeMaker
|
285
|
+
# extend DSLKit::Constant
|
286
|
+
#
|
287
|
+
# constant :on, :on
|
288
|
+
# constant :off, :off
|
289
|
+
#
|
290
|
+
# extend DSLKit::DSLAccessor
|
291
|
+
#
|
292
|
+
# dsl_accessor(:state) { off } # Note: the off constant from above is used
|
293
|
+
#
|
294
|
+
# dsl_accessor :allowed_states, :on, :off
|
295
|
+
#
|
296
|
+
# def process
|
297
|
+
# allowed_states.include?(state) or fail "Explode!!!"
|
298
|
+
# if state == on
|
299
|
+
# puts "Make coffee."
|
300
|
+
# else
|
301
|
+
# puts "Idle..."
|
302
|
+
# end
|
303
|
+
# end
|
304
|
+
# end
|
305
|
+
#
|
306
|
+
# cm = CoffeeMaker.new
|
307
|
+
# cm.instance_eval do
|
308
|
+
# state # => :off
|
309
|
+
# state on
|
310
|
+
# state # => :on
|
311
|
+
# process # => outputs "Make coffee."
|
312
|
+
# end
|
313
|
+
#
|
314
|
+
# Note that DSLKit::SymbolMaker is an alternative for DSLKit::Constant in
|
315
|
+
# this example. On the other hand SymbolMaker can make debugging more
|
316
|
+
# difficult.
|
317
|
+
module DSLAccessor
|
318
|
+
# This method creates a dsl accessor named _name_. If nothing else is given
|
319
|
+
# as argument it defaults to nil. If <i>*default</i> is given as a single
|
320
|
+
# value it is used as a default value, if more than one value is given the
|
321
|
+
# _default_ array is used as the default value. If no default value but a
|
322
|
+
# block _block_ is given as an argument, the block is executed everytime
|
323
|
+
# the accessor is read <b>in the context of the current instance</b>.
|
324
|
+
#
|
325
|
+
# After setting up the accessor, the set or default value can be retrieved
|
326
|
+
# by calling the method +name+. To set a value one can call <code>name
|
327
|
+
# :foo</code> to set the attribute value to <code>:foo</code> or
|
328
|
+
# <code>name(:foo, :bar)</code> to set it to <code>[ :foo, :bar ]</code>.
|
329
|
+
def dsl_accessor(name, *default, &block)
|
330
|
+
variable = "@#{name}"
|
331
|
+
define_method(name) do |*args|
|
332
|
+
if args.empty?
|
333
|
+
result = instance_variable_get(variable)
|
334
|
+
if result.nil?
|
335
|
+
if default.empty?
|
336
|
+
block && instance_eval(&block)
|
337
|
+
elsif default.size == 1
|
338
|
+
default.first
|
339
|
+
else
|
340
|
+
default
|
341
|
+
end
|
342
|
+
else
|
343
|
+
result
|
344
|
+
end
|
345
|
+
else
|
346
|
+
instance_variable_set(variable, args.size == 1 ? args.first : args)
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
# This method creates a dsl reader accessor, that behaves exactly like a
|
352
|
+
# #dsl_accessor but can only be read not set.
|
353
|
+
def dsl_reader(name, *default, &block)
|
354
|
+
variable = "@#{name}"
|
355
|
+
define_method(name) do |*args|
|
356
|
+
if args.empty?
|
357
|
+
result = instance_variable_get(variable)
|
358
|
+
if result.nil?
|
359
|
+
if default.empty?
|
360
|
+
block && instance_eval(&block)
|
361
|
+
elsif default.size == 1
|
362
|
+
default.first
|
363
|
+
else
|
364
|
+
default
|
365
|
+
end
|
366
|
+
else
|
367
|
+
result
|
368
|
+
end
|
369
|
+
else
|
370
|
+
raise ArgumentError, "wrong number of arguments (#{args.size} for 0)"
|
371
|
+
end
|
372
|
+
end
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
# This module can be included in another module/class. It generates a symbol
|
377
|
+
# for every missing method that was called in the context of this
|
378
|
+
# module/class.
|
379
|
+
module SymbolMaker
|
380
|
+
# Returns a symbol (_id_) for every missing method named _id_.
|
381
|
+
def method_missing(id, *args)
|
382
|
+
if args.empty?
|
383
|
+
id
|
384
|
+
else
|
385
|
+
super
|
386
|
+
end
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
# This module can be used to extend another module/class. It generates
|
391
|
+
# symbols for every missing constant under the namespace of this
|
392
|
+
# module/class.
|
393
|
+
module ConstantMaker
|
394
|
+
# Returns a symbol (_id_) for every missing constant named _id_.
|
395
|
+
def const_missing(id)
|
396
|
+
id
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
module BlankSlate
|
401
|
+
# Creates an anonymous blank slate class, that only responds to the methods
|
402
|
+
# <i>*ids</i>. ids can be Symbols, Strings, and Regexps that have to match
|
403
|
+
# the method name with #===.
|
404
|
+
def self.with(*ids)
|
405
|
+
ids = ids.map { |id| Regexp === id ? id : id.to_s }
|
406
|
+
klass = Class.new
|
407
|
+
klass.instance_eval do
|
408
|
+
instance_methods.each do |m|
|
409
|
+
undef_method m unless m =~ /^__/ or ids.any? { |i| i === m }
|
410
|
+
end
|
411
|
+
end
|
412
|
+
klass
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
# See examples/recipe.rb and examples/recipe2.rb how this works at the
|
417
|
+
# moment.
|
418
|
+
module Deflect
|
419
|
+
# The basic Deflect exception
|
420
|
+
class DeflectError < StandardError; end
|
421
|
+
|
422
|
+
class << self
|
423
|
+
extend DSLKit::ThreadLocal
|
424
|
+
|
425
|
+
# A thread local variable, that holds a DeflectorCollection instance for
|
426
|
+
# the current thread.
|
427
|
+
thread_local :deflecting
|
428
|
+
end
|
429
|
+
|
430
|
+
# A deflector is called with a _class_, a method _id_, and its
|
431
|
+
# <i>*args</i>.
|
432
|
+
class Deflector < Proc; end
|
433
|
+
|
434
|
+
# This class implements a collection of deflectors, to make them available
|
435
|
+
# by emulating Ruby's message dispatch.
|
436
|
+
class DeflectorCollection
|
437
|
+
def initialize
|
438
|
+
@classes = {}
|
439
|
+
end
|
440
|
+
|
441
|
+
# Add a new deflector _deflector_ for class _klass_ and method name _id_,
|
442
|
+
# and return self.
|
443
|
+
#
|
444
|
+
def add(klass, id, deflector)
|
445
|
+
k = @classes[klass]
|
446
|
+
k = @classes[klass] = {} unless k
|
447
|
+
k[id.to_s] = deflector
|
448
|
+
self
|
449
|
+
end
|
450
|
+
|
451
|
+
# Return true if messages are deflected for class _klass_ and method name
|
452
|
+
# _id_, otherwise return false.
|
453
|
+
def member?(klass, id)
|
454
|
+
!!(k = @classes[klass] and k.key?(id.to_s))
|
455
|
+
end
|
456
|
+
|
457
|
+
# Delete the deflecotor class _klass_ and method name _id_. Returns the
|
458
|
+
# deflector if any was found, otherwise returns true.
|
459
|
+
def delete(klass, id)
|
460
|
+
if k = @classes[klass]
|
461
|
+
d = k.delete id.to_s
|
462
|
+
@classes.delete klass if k.empty?
|
463
|
+
d
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
# Try to find a deflector for class _klass_ and method _id_ and return
|
468
|
+
# it. If none was found, return nil instead.
|
469
|
+
def find(klass, id)
|
470
|
+
klass.ancestors.find do |k|
|
471
|
+
if d = @classes[k] and d = d[id.to_s]
|
472
|
+
return d
|
473
|
+
end
|
474
|
+
end
|
475
|
+
end
|
476
|
+
end
|
477
|
+
|
478
|
+
# Start deflecting method calls named _id_ to the _from_ class using the
|
479
|
+
# Deflector instance deflector.
|
480
|
+
def deflect_start(from, id, deflector)
|
481
|
+
old = Thread.critical
|
482
|
+
Thread.critical = true
|
483
|
+
Deflect.deflecting ||= DeflectorCollection.new
|
484
|
+
Deflect.deflecting.member?(from, id) and
|
485
|
+
raise DeflectError, "#{from}##{id} is already deflected"
|
486
|
+
Deflect.deflecting.add(from, id, deflector)
|
487
|
+
from.class_eval do
|
488
|
+
define_method(id) do |*args|
|
489
|
+
if Deflect.deflecting and d = Deflect.deflecting.find(self.class, id)
|
490
|
+
Thread.critical = old
|
491
|
+
d.call(self, id, *args)
|
492
|
+
else
|
493
|
+
Thread.critical = old
|
494
|
+
super
|
495
|
+
end
|
496
|
+
end
|
497
|
+
end
|
498
|
+
ensure
|
499
|
+
Thread.critical = old
|
500
|
+
end
|
501
|
+
|
502
|
+
# Return true if method _id_ is deflected from class _from_, otherwise
|
503
|
+
# return false.
|
504
|
+
def self.deflect?(from, id)
|
505
|
+
Deflect.deflecting && Deflect.deflecting.member?(from, id)
|
506
|
+
end
|
507
|
+
|
508
|
+
# Return true if method _id_ is deflected from class _from_, otherwise
|
509
|
+
# return false.
|
510
|
+
def deflect?(from, id)
|
511
|
+
Deflect.deflect?(from, id)
|
512
|
+
end
|
513
|
+
|
514
|
+
# Start deflecting method calls named _id_ to the _from_ class using the
|
515
|
+
# Deflector instance deflector. After that yield to the given block and
|
516
|
+
# stop deflecting again.
|
517
|
+
def deflect(from, id, deflector)
|
518
|
+
old = Thread.critical
|
519
|
+
Thread.critical = true
|
520
|
+
deflect_start(from, id, deflector)
|
521
|
+
yield
|
522
|
+
ensure
|
523
|
+
deflect_stop(from, id)
|
524
|
+
Thread.critical = old
|
525
|
+
end
|
526
|
+
|
527
|
+
# Stop deflection method calls named _id_ to class _from_.
|
528
|
+
def deflect_stop(from, id)
|
529
|
+
old = Thread.critical
|
530
|
+
Thread.critical = true
|
531
|
+
Deflect.deflecting.delete(from, id) or
|
532
|
+
raise DeflectError, "#{from}##{id} is not deflected from"
|
533
|
+
from.instance_eval { remove_method id }
|
534
|
+
ensure
|
535
|
+
Thread.critical = old
|
536
|
+
end
|
537
|
+
end
|
538
|
+
end
|
data/lib/dslkit/rude.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# This file contains some "rude" defaults that tamper with Ruby's open classes
|
2
|
+
# to augment them with DSLKit methods. Although this shouldn't break anything, it's
|
3
|
+
# perhaps better to require 'dslkit/polite' instead and include/extend your
|
4
|
+
# classes with a finer granularity.
|
5
|
+
require 'dslkit/polite'
|
6
|
+
|
7
|
+
module DSLKit
|
8
|
+
class ::Module
|
9
|
+
include DSLKit::Constant
|
10
|
+
include DSLKit::DSLAccessor
|
11
|
+
include DSLKit::ClassMethod
|
12
|
+
end
|
13
|
+
|
14
|
+
class ::Object
|
15
|
+
include DSLKit::ThreadLocal
|
16
|
+
include DSLKit::ThreadGlobal
|
17
|
+
include DSLKit::InstanceExec
|
18
|
+
include DSLKit::Interpreter
|
19
|
+
include DSLKit::Deflect
|
20
|
+
include DSLKit::ThreadLocal
|
21
|
+
include DSLKit::Eigenclass
|
22
|
+
end
|
23
|
+
end
|
data/lib/dslkit.rb
ADDED
data/tests/runner.rb
ADDED