caesars 0.5.4 → 0.5.5

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.
Files changed (5) hide show
  1. data/CHANGES.txt +10 -0
  2. data/bin/example +26 -2
  3. data/caesars.gemspec +2 -2
  4. data/lib/caesars.rb +128 -63
  5. metadata +2 -2
data/CHANGES.txt CHANGED
@@ -1,6 +1,16 @@
1
1
  CAESAR -- CHANGES
2
2
 
3
3
 
4
+
5
+ #### 0.5.5 (2009-04-27) ###############################
6
+
7
+ * CHANGE: Caesars.chill and Caesars.forced_hash can now be used together.
8
+ * ADDED: Print error to STDERR when a duplicate key found for forced_hash keys
9
+ * ADDED: Caesars.forced_array
10
+ * CHANGE: Caesars.method_missing now stores and returns an empty Caesars::Hash
11
+ for known methods that are called (currently only ones defined by forced_array)
12
+
13
+
4
14
  #### 0.5.4 (2009-04-11) ###############################
5
15
 
6
16
  * FIXED: find_deferred would abort early because the safety limit
data/bin/example CHANGED
@@ -112,8 +112,6 @@ p @staff_fte.splashdown.sheila.salary.call(rand(100)) # => 549.77
112
112
  # EXAMPLE 3 -- External Config file
113
113
  #
114
114
 
115
- require 'caesars'
116
-
117
115
  class Food < Caesars
118
116
  chill :order
119
117
  end
@@ -137,3 +135,29 @@ p @config.keys # => [:food, :drink]
137
135
 
138
136
  @config.refresh
139
137
 
138
+
139
+ # ------------------------------------------------------------------
140
+ # EXAMPLE 4 -- Forced Array
141
+ #
142
+ class Shift < Caesars
143
+ forced_array :peoples
144
+ end
145
+
146
+ include Shift::DSL
147
+
148
+ shift do
149
+ peoples :tom, :jeff, :al
150
+ compare :tom, :jeff, :al
151
+ peoples :ada, :gary, :bo
152
+ end
153
+
154
+ p @shift.peoples[0] # => [:tom, :jeff, :al]
155
+ p @shift.compare[0] # => :tom
156
+ p @shift.compare # => [:tom, :jeff, :al]
157
+ p @shift.peoples[1] # => [:ada, :gary, :bo]
158
+ p @shift.compare[1] # => :jeff
159
+
160
+
161
+
162
+
163
+
data/caesars.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  @spec = Gem::Specification.new do |s|
2
2
  s.name = %q{caesars}
3
- s.version = "0.5.4"
4
- s.date = %q{2009-04-11}
3
+ s.version = "0.5.5"
4
+ s.date = %q{2009-04-27}
5
5
  s.specification_version = 1 if s.respond_to? :specification_version=
6
6
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
7
7
 
data/lib/caesars.rb CHANGED
@@ -7,12 +7,27 @@
7
7
  # See bin/example
8
8
  #
9
9
  class Caesars
10
- VERSION = "0.5.4"
10
+ VERSION = 0.5
11
11
  @@debug = false
12
-
12
+ @@chilled = {}
13
+ @@forced_array = {}
14
+
13
15
  def Caesars.enable_debug; @@debug = true; end
14
16
  def Caesars.disable_debug; @@debug = false; end
15
17
  def Caesars.debug?; @@debug; end
18
+ # Is the given +name+ chilled?
19
+ # See Caesars.chill
20
+ def Caesars.chilled?(name)
21
+ return false unless name
22
+ @@chilled.has_key?(name.to_sym)
23
+ end
24
+ # Is the given +name+ a forced array?
25
+ # See Caesars.forced_array
26
+ def Caesars.forced_array?(name)
27
+ return false unless name
28
+ @@forced_array.has_key?(name.to_sym)
29
+ end
30
+
16
31
 
17
32
  # A subclass of ::Hash that provides method names for hash parameters.
18
33
  # It's like a lightweight OpenStruct.
@@ -46,6 +61,10 @@ class Caesars
46
61
  # An instance of Caesars::Hash which contains the data specified by your DSL
47
62
  attr_accessor :caesars_properties
48
63
 
64
+ class Error < RuntimeError
65
+ def initialize(obj=nil); @obj = obj; end
66
+ def message; "#{self.class}: #{@obj}"; end
67
+ end
49
68
 
50
69
  def initialize(name=nil)
51
70
  @caesars_name = name if name
@@ -207,81 +226,76 @@ class Caesars
207
226
  @caesars_properties[name] = value
208
227
  end
209
228
 
210
- # This method handles all of the attributes that do not contain blocks.
229
+ # This method handles all of the attributes that are not forced hashes
211
230
  # It's used in the DSL for handling attributes dyanamically (that weren't defined
212
- # previously) and also in subclasses of Caesar for returning the appropriate
231
+ # previously) and also in subclasses of Caesars for returning the appropriate
213
232
  # attribute values.
214
233
  def method_missing(meth, *args, &b)
234
+
215
235
  # Handle the setter, attribute=
216
236
  if meth.to_s =~ /=$/ && @caesars_properties.has_key?(meth.to_s.chop.to_sym)
217
237
  return @caesars_properties[meth.to_s.chop.to_sym] = (args.size == 1) ? args.first : args
218
238
  end
219
239
 
220
240
  return @caesars_properties[meth] if @caesars_properties.has_key?(meth) && args.empty? && b.nil?
221
- return nil if args.empty? && b.nil?
241
+
242
+ # We there are no args and no block, we return nil. This is useful
243
+ # for calls to methods on a Caesars::Hash object that don't have a
244
+ # value (so we cam treat self[:someval] the same as self.someval).
245
+ if args.empty? && b.nil?
246
+
247
+ # We make an exception for methods that we are already expecting.
248
+ if Caesars.forced_array?(meth)
249
+ return @caesars_pointer[meth] ||= Caesars::Hash.new
250
+ else
251
+ return nil
252
+ end
253
+ end
222
254
 
223
255
  if b
224
256
  # Use the name of the bloody method if no name is supplied.
225
257
  args << meth if args.empty?
258
+
226
259
  args.each do |name|
227
260
  prev = @caesars_pointer
228
- #(@caesars_pointer[:"#{meth}_values"] ||= []) << name
229
261
  @caesars_pointer[name] ||= Caesars::Hash.new
230
- @caesars_pointer = @caesars_pointer[name]
231
- begin
232
- b.call if b
233
- rescue ArgumentError, SyntaxError => ex
234
- STDERR.puts "CAESARS: error in #{meth} (#{args.join(', ')})"
235
- raise ex
262
+ if Caesars.chilled?(meth)
263
+ @caesars_pointer[name] = b
264
+ else
265
+ @caesars_pointer = @caesars_pointer[name]
266
+ begin
267
+ b.call if b
268
+ rescue ArgumentError, SyntaxError => ex
269
+ STDERR.puts "CAESARS: error in #{meth} (#{args.join(', ')})"
270
+ raise ex
271
+ end
272
+ @caesars_pointer = prev
236
273
  end
237
- @caesars_pointer = prev
238
274
  end
239
-
275
+
276
+ # We've seen this attribute before, add the valued to the existing element
240
277
  elsif @caesars_pointer.kind_of?(Hash) && @caesars_pointer[meth]
241
278
 
242
- @caesars_pointer[meth] = [@caesars_pointer[meth]] unless @caesars_pointer[meth].is_a?(Array)
243
- @caesars_pointer[meth] += args
244
- elsif !args.empty?
245
- @caesars_pointer[meth] = args.size == 1 ? args.first : args
246
- end
247
-
248
- end
249
-
250
- # A class method which can be used by subclasses to specify which methods
251
- # should delay execution of their blocks. Here's an example:
252
- #
253
- # class Food < Caesars
254
- # chill :count
255
- # end
256
- #
257
- # food do
258
- # taste :delicious
259
- # count do |items|
260
- # puts items + 2
261
- # end
262
- # end
263
- #
264
- # @config.food.count.call(3) # => 5
265
- #
266
- def self.chill(caesars_meth)
267
- module_eval %Q{
268
- def #{caesars_meth}(*caesars_names,&b)
269
- # caesars.toplevel.unnamed_chilled_attribute
270
- return @caesars_properties[:'#{caesars_meth}'] if @caesars_properties.has_key?(:'#{caesars_meth}') && caesars_names.empty? && b.nil?
271
-
272
- # Use the name of the chilled method if no name is supplied.
273
- caesars_names << :'#{caesars_meth}' if caesars_names.empty?
274
-
275
- caesars_names.each do |name|
276
- @caesars_pointer[name] = b
279
+ if Caesars.forced_array?(meth)
280
+ @caesars_pointer[meth] ||= []
281
+ @caesars_pointer[meth] << args
282
+ else
283
+ # Make the element an Array once there's more than a single value
284
+ unless @caesars_pointer[meth].is_a?(Array)
285
+ @caesars_pointer[meth] = [@caesars_pointer[meth]]
277
286
  end
287
+ @caesars_pointer[meth] += args
288
+ end
278
289
 
279
- @caesars_pointer[:'#{caesars_meth}']
290
+ elsif !args.empty?
291
+ if Caesars.forced_array?(meth)
292
+ @caesars_pointer[meth] = [args]
293
+ else
294
+ @caesars_pointer[meth] = args.size == 1 ? args.first : args
280
295
  end
281
- }
282
- nil
283
- end
296
+ end
284
297
 
298
+ end
285
299
 
286
300
 
287
301
  # Force the specified keyword to always be treated as a hash.
@@ -311,16 +325,64 @@ class Caesars
311
325
  prev = @caesars_pointer
312
326
  @caesars_pointer[:'#{caesars_meth}'] ||= Caesars::Hash.new
313
327
  hash = Caesars::Hash.new
314
- @caesars_pointer = hash
315
- b.call if b
316
- @caesars_pointer = prev
317
- @caesars_pointer[:'#{caesars_meth}'][caesars_name] = hash
318
- @caesars_pointer = prev
328
+ if @caesars_pointer[:'#{caesars_meth}'].has_key?(caesars_name)
329
+ STDERR.puts "duplicate key ignored: \#{caesars_name}"
330
+ return
331
+ end
332
+
333
+ @caesars_pointer = hash # This is needed but I don't know why
334
+ if b
335
+ if Caesars.chilled?(:'#{caesars_meth}')
336
+ @caesars_pointer[:'#{caesars_meth}'][caesars_name] = b
337
+ else
338
+ b.call
339
+ @caesars_pointer = prev
340
+ @caesars_pointer[:'#{caesars_meth}'][caesars_name] = hash
341
+ end
342
+ @caesars_pointer = prev
343
+ end
319
344
  end
320
345
  }
321
346
  nil
322
-
323
-
347
+ end
348
+
349
+ # Specify a method that should delay execution of its block.
350
+ # Here's an example:
351
+ #
352
+ # class Food < Caesars
353
+ # chill :count
354
+ # end
355
+ #
356
+ # food do
357
+ # taste :delicious
358
+ # count do |items|
359
+ # puts items + 2
360
+ # end
361
+ # end
362
+ #
363
+ # @config.food.count.call(3) # => 5
364
+ #
365
+ def self.chill(caesars_meth)
366
+ @@chilled[caesars_meth.to_sym] = true
367
+ nil
368
+ end
369
+
370
+ # Specify a method that should store it's args as nested Arrays
371
+ # Here's an example:
372
+ #
373
+ # class Food < Caesars
374
+ # forced_array :sauce
375
+ # end
376
+ #
377
+ # food do
378
+ # taste :delicious
379
+ # sauce
380
+ # end
381
+ #
382
+ # @config.food.count.call(3) # => 5
383
+ def self.forced_array(caesars_meth)
384
+ @@forced_array[caesars_meth.to_sym] = true
385
+ nil
324
386
  end
325
387
 
326
388
  # Executes automatically when Caesars is subclassed. This creates the
@@ -439,10 +501,13 @@ class Caesars::Config
439
501
 
440
502
  postprocess
441
503
 
504
+ rescue Caesars::Error => ex
505
+ STDERR.puts ex.message
506
+ STDERR.puts ex.backtrace if Caesars.debug?
442
507
  rescue ArgumentError, SyntaxError => ex
443
- puts "Syntax error in #{path}."
444
- puts ex.message
445
- puts ex.backtrace if Caesars.debug?
508
+ STDERR.puts "Syntax error in #{path}."
509
+ STDERR.puts ex.message
510
+ STDERR.puts ex.backtrace if Caesars.debug?
446
511
  exit 1
447
512
  end
448
513
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: caesars
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.4
4
+ version: 0.5.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Delano Mandelbaum
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-04-11 00:00:00 -04:00
12
+ date: 2009-04-27 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies: []
15
15