Empact-roxml 2.4.3 → 2.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +65 -0
- data/Manifest.txt +11 -6
- data/README.rdoc +48 -26
- data/Rakefile +5 -2
- data/TODO +30 -31
- data/examples/active_record.rb +70 -0
- data/examples/amazon.rb +1 -1
- data/examples/current_weather.rb +1 -1
- data/examples/library.rb +40 -0
- data/examples/posts.rb +8 -8
- data/examples/twitter.rb +2 -2
- data/examples/xml/active_record.xml +70 -0
- data/lib/roxml.rb +174 -174
- data/lib/roxml/definition.rb +165 -89
- data/lib/roxml/extensions/deprecation.rb +5 -0
- data/lib/roxml/extensions/string/conversions.rb +2 -3
- data/lib/roxml/hash_definition.rb +26 -25
- data/lib/roxml/xml.rb +15 -6
- data/lib/roxml/xml/parsers/libxml.rb +14 -6
- data/lib/roxml/xml/parsers/rexml.rb +16 -5
- data/lib/roxml/xml/references.rb +14 -17
- data/roxml.gemspec +14 -5
- data/spec/definition_spec.rb +563 -0
- data/spec/examples/active_record_spec.rb +40 -0
- data/spec/examples/library_spec.rb +41 -0
- data/spec/roxml_spec.rb +372 -0
- data/spec/shared_specs.rb +15 -0
- data/spec/spec_helper.rb +21 -4
- data/spec/string_spec.rb +15 -0
- data/spec/xml/parser_spec.rb +47 -0
- data/test/fixtures/book_valid.xml +1 -1
- data/test/fixtures/person_with_guarded_mothers.xml +3 -3
- data/test/mocks/mocks.rb +57 -45
- data/test/test_helper.rb +1 -1
- data/test/unit/definition_test.rb +161 -12
- data/test/unit/deprecations_test.rb +97 -0
- data/test/unit/to_xml_test.rb +30 -1
- data/test/unit/xml_bool_test.rb +15 -3
- data/test/unit/xml_construct_test.rb +6 -6
- data/test/unit/xml_hash_test.rb +18 -0
- data/test/unit/xml_initialize_test.rb +6 -3
- data/test/unit/xml_namespace_test.rb +1 -0
- data/test/unit/xml_object_test.rb +66 -5
- data/test/unit/xml_text_test.rb +3 -0
- metadata +57 -24
- data/test/unit/array_test.rb +0 -16
- data/test/unit/freeze_test.rb +0 -71
- data/test/unit/inheritance_test.rb +0 -63
- data/test/unit/overriden_output_test.rb +0 -33
- data/test/unit/roxml_test.rb +0 -60
- data/test/unit/string_test.rb +0 -11
data/lib/roxml/definition.rb
CHANGED
@@ -1,8 +1,19 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'hash_definition')
|
2
2
|
|
3
|
+
class Module
|
4
|
+
def bool_attr_reader(*attrs)
|
5
|
+
attrs.each do |attr|
|
6
|
+
define_method :"#{attr}?" do
|
7
|
+
instance_variable_get(:"@#{attr}") || false
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
3
13
|
module ROXML
|
4
14
|
class Definition # :nodoc:
|
5
|
-
attr_reader :name, :type, :hash, :blocks, :accessor, :to_xml
|
15
|
+
attr_reader :name, :type, :wrapper, :hash, :blocks, :accessor, :to_xml
|
16
|
+
bool_attr_reader :name_explicit, :array, :cdata, :required, :frozen
|
6
17
|
|
7
18
|
class << self
|
8
19
|
def silence_xml_name_warning?
|
@@ -16,21 +27,24 @@ module ROXML
|
|
16
27
|
|
17
28
|
def initialize(sym, *args, &block)
|
18
29
|
@accessor = sym
|
19
|
-
@
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
if @opts.has_key?(:readonly)
|
25
|
-
raise ArgumentError, "There is no 'readonly' option. You probably mean to use :frozen => true"
|
30
|
+
if @accessor.to_s.ends_with?('_on')
|
31
|
+
ActiveSupport::Deprecation.warn "In 3.0, attributes with names ending with _on will default to Date type, rather than :text"
|
32
|
+
end
|
33
|
+
if @accessor.to_s.ends_with?('_at')
|
34
|
+
ActiveSupport::Deprecation.warn "In 3.0, attributes with names ending with _at will default to DateTime type, rather than :text"
|
26
35
|
end
|
27
36
|
|
28
|
-
|
29
|
-
|
37
|
+
opts = extract_options!(args)
|
38
|
+
opts[:as] ||= :bool if @accessor.to_s.ends_with?('?')
|
30
39
|
|
31
|
-
@
|
32
|
-
@opts[:as]
|
40
|
+
@array = opts[:as].is_a?(Array) || extract_from_as(opts, :array, "Please use [] around your usual type declaration")
|
41
|
+
@blocks = collect_blocks(block, opts[:as])
|
33
42
|
|
43
|
+
if opts.has_key?(:readonly)
|
44
|
+
raise ArgumentError, "There is no 'readonly' option. You probably mean to use :frozen => true"
|
45
|
+
end
|
46
|
+
|
47
|
+
@type = extract_type(args, opts)
|
34
48
|
if @type.try(:xml_name_without_deprecation?)
|
35
49
|
unless self.class.silence_xml_name_warning?
|
36
50
|
warn "WARNING: As of 2.3, a breaking change has been in the naming of sub-objects. " +
|
@@ -38,14 +52,22 @@ module ROXML
|
|
38
52
|
"Use :from on the parent declaration to override this behavior. Set ROXML::SILENCE_XML_NAME_WARNING to avoid this message."
|
39
53
|
self.class.silence_xml_name_warning!
|
40
54
|
end
|
41
|
-
|
42
|
-
else
|
43
|
-
@opts[:from] ||= variable_name
|
55
|
+
opts[:from] ||= @type.tag_name
|
44
56
|
end
|
45
57
|
|
46
|
-
|
58
|
+
if opts[:from] == :content
|
59
|
+
opts[:from] = '.'
|
60
|
+
elsif opts[:from] == :name
|
61
|
+
opts[:from] = '*'
|
62
|
+
elsif opts[:from] == :attr
|
63
|
+
@type = :attr
|
64
|
+
opts[:from] = nil
|
65
|
+
elsif opts[:from].to_s.starts_with?('@')
|
66
|
+
@type = :attr
|
67
|
+
opts[:from].sub!('@', '')
|
68
|
+
end
|
47
69
|
|
48
|
-
@name =
|
70
|
+
@name = (opts[:from] || variable_name).to_s
|
49
71
|
@name = @name.singularize if hash? || array?
|
50
72
|
if hash? && (hash.key.name? || hash.value.name?)
|
51
73
|
@name = '*'
|
@@ -55,63 +77,43 @@ module ROXML
|
|
55
77
|
end
|
56
78
|
|
57
79
|
def variable_name
|
58
|
-
accessor.to_s.
|
80
|
+
accessor.to_s.chomp('?')
|
59
81
|
end
|
60
82
|
|
61
83
|
def hash
|
62
|
-
|
84
|
+
if hash?
|
85
|
+
@type.wrapper ||= name
|
86
|
+
@type
|
87
|
+
end
|
63
88
|
end
|
64
89
|
|
65
90
|
def hash?
|
66
|
-
@type
|
91
|
+
@type.is_a?(HashDefinition)
|
67
92
|
end
|
68
93
|
|
69
94
|
def name?
|
70
95
|
@name == '*'
|
71
96
|
end
|
72
97
|
|
73
|
-
def name_explicit?
|
74
|
-
@name_explicit
|
75
|
-
end
|
76
|
-
|
77
98
|
def content?
|
78
|
-
@
|
79
|
-
end
|
80
|
-
|
81
|
-
def array?
|
82
|
-
@opts[:as].include? :array
|
83
|
-
end
|
84
|
-
|
85
|
-
def cdata?
|
86
|
-
@opts[:as].include? :cdata
|
87
|
-
end
|
88
|
-
|
89
|
-
def wrapper
|
90
|
-
@opts[:in]
|
91
|
-
end
|
92
|
-
|
93
|
-
def required?
|
94
|
-
@opts[:required]
|
95
|
-
end
|
96
|
-
|
97
|
-
def freeze?
|
98
|
-
@opts[:frozen]
|
99
|
+
@name == '.'
|
99
100
|
end
|
100
101
|
|
101
102
|
def default
|
102
|
-
@default
|
103
|
-
|
103
|
+
if @default.nil?
|
104
|
+
@default = [] if array?
|
105
|
+
@default = {} if hash?
|
106
|
+
end
|
104
107
|
@default.duplicable? ? @default.dup : @default
|
105
108
|
end
|
106
109
|
|
107
110
|
def to_ref(inst)
|
108
111
|
case type
|
109
|
-
when :attr
|
110
|
-
when :
|
111
|
-
when
|
112
|
-
when
|
113
|
-
|
114
|
-
else XMLObjectRef
|
112
|
+
when :attr then XMLAttributeRef
|
113
|
+
when :text then XMLTextRef
|
114
|
+
when HashDefinition then XMLHashRef
|
115
|
+
when Symbol then raise ArgumentError, "Invalid type argument #{type}"
|
116
|
+
else XMLObjectRef
|
115
117
|
end.new(self, inst)
|
116
118
|
end
|
117
119
|
|
@@ -127,13 +129,13 @@ module ROXML
|
|
127
129
|
|
128
130
|
BLOCK_TO_FLOAT = lambda do |val|
|
129
131
|
all(val) do |v|
|
130
|
-
Float(v) unless
|
132
|
+
Float(v) unless v.blank?
|
131
133
|
end
|
132
134
|
end
|
133
135
|
|
134
136
|
BLOCK_TO_INT = lambda do |val|
|
135
137
|
all(val) do |v|
|
136
|
-
Integer(v) unless
|
138
|
+
Integer(v) unless v.blank?
|
137
139
|
end
|
138
140
|
end
|
139
141
|
|
@@ -147,30 +149,20 @@ module ROXML
|
|
147
149
|
default
|
148
150
|
end
|
149
151
|
end
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
end
|
154
|
-
|
155
|
-
BLOCK_SHORTHANDS = {
|
152
|
+
|
153
|
+
CORE_BLOCK_SHORTHANDS = {
|
154
|
+
# Core Shorthands
|
156
155
|
:integer => BLOCK_TO_INT, # deprecated
|
157
156
|
Integer => BLOCK_TO_INT,
|
158
157
|
:float => BLOCK_TO_FLOAT, # deprecated
|
159
158
|
Float => BLOCK_TO_FLOAT,
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
end
|
164
|
-
end,
|
165
|
-
DateTime => lambda do |val|
|
166
|
-
if defined?(DateTime)
|
167
|
-
all(val) {|v| DateTime.parse(v) unless blank_string?(v) }
|
159
|
+
Fixnum => lambda do |val|
|
160
|
+
all(val) do |v|
|
161
|
+
v.to_i unless v.blank?
|
168
162
|
end
|
169
163
|
end,
|
170
164
|
Time => lambda do |val|
|
171
|
-
|
172
|
-
all(val) {|v| Time.parse(v) unless blank_string?(v) }
|
173
|
-
end
|
165
|
+
all(val) {|v| Time.parse(v) unless v.blank? }
|
174
166
|
end,
|
175
167
|
|
176
168
|
:bool => nil,
|
@@ -186,22 +178,54 @@ module ROXML
|
|
186
178
|
end
|
187
179
|
}
|
188
180
|
|
181
|
+
def self.block_shorthands
|
182
|
+
# dynamically load these shorthands at class definition time, but
|
183
|
+
# only if they're already availbable
|
184
|
+
returning CORE_BLOCK_SHORTHANDS do |blocks|
|
185
|
+
blocks.reverse_merge!(BigDecimal => lambda do |val|
|
186
|
+
all(val) do |v|
|
187
|
+
BigDecimal.new(v) unless v.blank?
|
188
|
+
end
|
189
|
+
end) if defined?(BigDecimal)
|
190
|
+
|
191
|
+
blocks.reverse_merge!(DateTime => lambda do |val|
|
192
|
+
if defined?(DateTime)
|
193
|
+
all(val) {|v| DateTime.parse(v) unless v.blank? }
|
194
|
+
end
|
195
|
+
end) if defined?(DateTime)
|
196
|
+
|
197
|
+
blocks.reverse_merge!(Date => lambda do |val|
|
198
|
+
if defined?(Date)
|
199
|
+
all(val) {|v| Date.parse(v) unless v.blank? }
|
200
|
+
end
|
201
|
+
end) if defined?(Date)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
189
205
|
def collect_blocks(block, as)
|
190
|
-
ActiveSupport::Deprecation.warn ":as => :float is deprecated. Use :as => Float instead" if as
|
191
|
-
ActiveSupport::Deprecation.warn ":as => :integer is deprecated. Use :as => Integer instead" if as
|
206
|
+
ActiveSupport::Deprecation.warn ":as => :float is deprecated. Use :as => Float instead" if as == :float
|
207
|
+
ActiveSupport::Deprecation.warn ":as => :integer is deprecated. Use :as => Integer instead" if as == :integer
|
208
|
+
|
209
|
+
if as.is_a?(Array)
|
210
|
+
unless as.one? || as.empty?
|
211
|
+
raise ArgumentError, "multiple :as types (#{as.map(&:inspect).join(', ')}) is not supported. Use a block if you want more complicated behavior."
|
212
|
+
end
|
192
213
|
|
193
|
-
|
194
|
-
if shorthands.size > 1
|
195
|
-
raise ArgumentError, "multiple block shorthands supplied #{shorthands.map(&:to_s).join(', ')}"
|
214
|
+
as = as.first
|
196
215
|
end
|
197
216
|
|
198
|
-
|
199
|
-
if shorthand == :bool
|
217
|
+
if as == :bool
|
200
218
|
# if a second block is present, and we can't coerce the xml value
|
201
219
|
# to bool, we need to be able to pass it to the user-provided block
|
202
|
-
|
220
|
+
as = (block ? :bool_combined : :bool_standalone)
|
203
221
|
end
|
204
|
-
|
222
|
+
as = self.class.block_shorthands.fetch(as) do
|
223
|
+
unless as.respond_to?(:from_xml) || as.try(:first).respond_to?(:from_xml) || (as.is_a?(Hash) && !(as.keys & HASH_KEYS).empty?)
|
224
|
+
ActiveSupport::Deprecation.warn "#{as.inspect} is not a valid type declaration. ROXML will raise in this case in version 3.0" unless as.nil?
|
225
|
+
end
|
226
|
+
nil
|
227
|
+
end
|
228
|
+
[as, block].compact
|
205
229
|
end
|
206
230
|
|
207
231
|
def extract_options!(args)
|
@@ -210,21 +234,60 @@ module ROXML
|
|
210
234
|
args.push(opts)
|
211
235
|
opts = {}
|
212
236
|
end
|
237
|
+
|
238
|
+
@default = opts.delete(:else)
|
239
|
+
@to_xml = opts.delete(:to_xml)
|
240
|
+
@name_explicit = opts.has_key?(:from) && opts[:from].is_a?(String)
|
241
|
+
@cdata = opts.delete(:cdata)
|
242
|
+
@required = opts.delete(:required)
|
243
|
+
@frozen = opts.delete(:frozen)
|
244
|
+
@wrapper = opts.delete(:in)
|
245
|
+
|
246
|
+
@cdata ||= extract_from_as(opts, :cdata, "Please use :cdata => true")
|
247
|
+
|
248
|
+
if opts[:as].is_a?(Array) && opts[:as].size > 1
|
249
|
+
ActiveSupport::Deprecation.warn ":as should point to a single item. #{opts[:as].join(', ')} should be declared some other way."
|
250
|
+
end
|
251
|
+
|
213
252
|
opts
|
214
253
|
end
|
215
254
|
|
216
|
-
def
|
217
|
-
|
255
|
+
def extract_from_as(opts, entry, message)
|
256
|
+
# remove with deprecateds...
|
257
|
+
if [*opts[:as]].include?(entry)
|
258
|
+
ActiveSupport::Deprecation.warn ":as => #{entry.inspect} is deprecated. #{message}"
|
259
|
+
if opts[:as] == entry
|
260
|
+
opts[:as] = nil
|
261
|
+
else
|
262
|
+
opts[:as].delete(entry)
|
263
|
+
end
|
264
|
+
true
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def extract_type(args, opts)
|
269
|
+
types = (opts.keys & TYPE_KEYS)
|
218
270
|
# type arg
|
219
271
|
if args.one? && types.empty?
|
220
272
|
type = args.first
|
221
273
|
if type.is_a? Array
|
222
|
-
|
223
|
-
|
274
|
+
ActiveSupport::Deprecation.warn "Array declarations should be passed as the :as parameter, for future release."
|
275
|
+
@array = true
|
276
|
+
return type.first || :text
|
224
277
|
elsif type.is_a? Hash
|
225
|
-
|
226
|
-
return
|
278
|
+
ActiveSupport::Deprecation.warn "Hash declarations should be passed as the :as parameter, for future release."
|
279
|
+
return HashDefinition.new(type)
|
280
|
+
elsif type == :content
|
281
|
+
ActiveSupport::Deprecation.warn ":content as a type declaration is deprecated. Use :from => '.' or :from => :content instead"
|
282
|
+
opts[:from] = :content
|
283
|
+
return :text
|
284
|
+
elsif type == :attr
|
285
|
+
ActiveSupport::Deprecation.warn ":attr as a type declaration is deprecated. Use :from => '@attr_name' or :from => :attr instead"
|
286
|
+
opts[:from].sub!('@', '') if opts[:from].to_s.starts_with?('@') # this is added back next line...
|
287
|
+
opts[:from] = opts[:from].nil? ? :attr : "@#{opts[:from]}"
|
288
|
+
return :attr
|
227
289
|
else
|
290
|
+
ActiveSupport::Deprecation.warn "Type declarations should be passed as the :as parameter, for future release."
|
228
291
|
return type
|
229
292
|
end
|
230
293
|
end
|
@@ -234,9 +297,22 @@ module ROXML
|
|
234
297
|
"an options hash, with the type and options optional"
|
235
298
|
end
|
236
299
|
|
300
|
+
if opts[:as].is_a?(Hash)
|
301
|
+
return HashDefinition.new(opts[:as])
|
302
|
+
elsif opts[:as].respond_to?(:from_xml)
|
303
|
+
return opts[:as]
|
304
|
+
elsif opts[:as].is_a?(Array) && opts[:as].first.respond_to?(:from_xml)
|
305
|
+
@array = true
|
306
|
+
return opts[:as].first
|
307
|
+
end
|
308
|
+
|
237
309
|
# type options
|
238
310
|
if types.one?
|
239
|
-
|
311
|
+
opts[:from] = opts.delete(types.first)
|
312
|
+
if opts[:from] == :content
|
313
|
+
opts[:from] = 'content'
|
314
|
+
ActiveSupport::Deprecation.warn ":content is now a reserved as an alias for '.'. Use the string 'content' instead"
|
315
|
+
end
|
240
316
|
types.first
|
241
317
|
elsif types.empty?
|
242
318
|
:text
|
@@ -245,4 +321,4 @@ module ROXML
|
|
245
321
|
end
|
246
322
|
end
|
247
323
|
end
|
248
|
-
end
|
324
|
+
end
|
@@ -6,6 +6,11 @@ require 'active_support/version'
|
|
6
6
|
module ActiveSupport # :nodoc:all
|
7
7
|
module Deprecation
|
8
8
|
class << self
|
9
|
+
def warn_with_internals_exclusion(message = nil, callstack = caller)
|
10
|
+
warn_without_internals_exclusion(message, callstack.reject {|line| line =~ /\/roxml(-[\d\.]+)?\/lib\// })
|
11
|
+
end
|
12
|
+
alias_method_chain :warn, :internals_exclusion
|
13
|
+
|
9
14
|
if VERSION::MAJOR <= 2 && VERSION::MINOR <= 1
|
10
15
|
def deprecation_message(callstack, message = nil)
|
11
16
|
message ||= "You are using deprecated behavior which will be removed from the next major or minor release"
|
@@ -17,6 +17,7 @@ module ROXML
|
|
17
17
|
self
|
18
18
|
end
|
19
19
|
end
|
20
|
+
deprecate :to_utf
|
20
21
|
|
21
22
|
#
|
22
23
|
# Convert this string to iso-8850-1
|
@@ -29,14 +30,12 @@ module ROXML
|
|
29
30
|
self
|
30
31
|
end
|
31
32
|
end
|
33
|
+
deprecate :to_latin
|
32
34
|
end
|
33
35
|
end
|
34
36
|
end
|
35
37
|
end
|
36
38
|
|
37
|
-
class Object
|
38
|
-
end
|
39
|
-
|
40
39
|
class String
|
41
40
|
def between(separator, &block)
|
42
41
|
split(separator).collect(&block).join(separator)
|
@@ -3,20 +3,21 @@ module ROXML
|
|
3
3
|
TYPE_KEYS = [:attr, :text, :hash, :content].freeze
|
4
4
|
|
5
5
|
class HashDefinition # :nodoc:
|
6
|
-
attr_reader :key, :value
|
6
|
+
attr_reader :key, :value
|
7
|
+
attr_accessor :wrapper
|
7
8
|
|
8
|
-
def initialize(opts
|
9
|
+
def initialize(opts)
|
9
10
|
unless (invalid_keys = opts.keys - HASH_KEYS).empty?
|
10
11
|
raise ArgumentError, "Invalid Hash description keys: #{invalid_keys.join(', ')}"
|
11
12
|
end
|
12
13
|
|
13
|
-
@wrapper = wrapper
|
14
14
|
if opts.has_key? :attrs
|
15
|
-
|
16
|
-
@
|
15
|
+
ActiveSupport::Deprecation.warn(":as => {:attrs} is going away in 3.0. Use explicit :key and :value instead.")
|
16
|
+
@key = to_hash_args(opts, :from => "@#{opts[:attrs][0]}")
|
17
|
+
@value = to_hash_args(opts, :from => "@#{opts[:attrs][1]}")
|
17
18
|
else
|
18
|
-
@key = to_hash_args opts,
|
19
|
-
@value = to_hash_args opts,
|
19
|
+
@key = to_hash_args opts, fetch_element(opts, :key)
|
20
|
+
@value = to_hash_args opts, fetch_element(opts, :value)
|
20
21
|
end
|
21
22
|
end
|
22
23
|
|
@@ -24,32 +25,32 @@ module ROXML
|
|
24
25
|
def fetch_element(opts, what)
|
25
26
|
case opts[what]
|
26
27
|
when Hash
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
28
|
+
if opts[what].keys.one?
|
29
|
+
ActiveSupport::Deprecation.warn(":as => {:key => {Type => 'name'} ... } is going away in 3.0. Use explicit :key => {:from => 'name', :as => Type} instead.")
|
30
|
+
type = opts[what].keys.first
|
31
|
+
case type
|
32
|
+
when :attr
|
33
|
+
{:from => "@#{opts[what][type]}"}
|
34
|
+
when :text
|
35
|
+
{:from => opts[what][type]}
|
36
|
+
else
|
37
|
+
{:as => type, :from => opts[what][type]}
|
38
|
+
end
|
39
|
+
else
|
40
|
+
opts[what]
|
41
|
+
end
|
42
|
+
when String, Symbol
|
43
|
+
{:from => opts[what]}
|
38
44
|
else
|
39
45
|
raise ArgumentError, "unrecognized hash parameter: #{what} => #{opts[what]}"
|
40
46
|
end
|
41
47
|
end
|
42
48
|
|
43
|
-
def to_hash_args(args,
|
49
|
+
def to_hash_args(args, opts)
|
44
50
|
args = [args] unless args.is_a? Array
|
45
51
|
|
46
52
|
if args.one? && !(args.first.keys & HASH_KEYS).empty?
|
47
|
-
opts
|
48
|
-
if type == :content
|
49
|
-
opts[:type] = :text
|
50
|
-
(opts[:as] ||= []) << :content
|
51
|
-
end
|
52
|
-
Definition.new(name, opts)
|
53
|
+
Definition.new(nil, opts)
|
53
54
|
else
|
54
55
|
opts = args.extract_options!
|
55
56
|
raise opts.inspect
|