icss 0.1.3 → 0.3.2

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 (98) hide show
  1. data/.watchr +35 -3
  2. data/CHANGELOG.md +38 -0
  3. data/Gemfile +19 -14
  4. data/README.md +296 -0
  5. data/Rakefile +2 -6
  6. data/TODO.md +13 -0
  7. data/VERSION +1 -1
  8. data/examples/avro_examples/complicated.icss.yaml +14 -13
  9. data/examples/bnc.icss.yaml +70 -0
  10. data/examples/chronic.icss.yaml +3 -3
  11. data/examples/license.icss.yaml +7 -0
  12. data/examples/source1.icss.yaml +4 -0
  13. data/examples/source2.icss.yaml +4 -0
  14. data/examples/test_icss.yaml +67 -0
  15. data/icss.gemspec +103 -43
  16. data/lib/icss.rb +37 -15
  17. data/lib/icss/core_types.rb +19 -0
  18. data/lib/icss/error.rb +4 -0
  19. data/{init.rb → lib/icss/init.rb} +0 -0
  20. data/lib/icss/message.rb +124 -66
  21. data/lib/icss/message/message_sample.rb +144 -0
  22. data/lib/icss/protocol.rb +184 -131
  23. data/lib/icss/protocol/code_asset.rb +18 -0
  24. data/lib/icss/protocol/data_asset.rb +23 -0
  25. data/lib/icss/protocol/license.rb +41 -0
  26. data/lib/icss/protocol/source.rb +37 -0
  27. data/lib/icss/protocol/target.rb +68 -0
  28. data/lib/icss/receiver_model.rb +24 -0
  29. data/lib/icss/receiver_model/active_model_shim.rb +36 -0
  30. data/lib/icss/receiver_model/acts_as_catalog.rb +170 -0
  31. data/lib/icss/receiver_model/acts_as_hash.rb +177 -0
  32. data/lib/icss/receiver_model/acts_as_loadable.rb +47 -0
  33. data/lib/icss/receiver_model/acts_as_tuple.rb +100 -0
  34. data/lib/icss/receiver_model/locale/en.yml +27 -0
  35. data/lib/icss/receiver_model/to_geo_json.rb +19 -0
  36. data/lib/icss/receiver_model/tree_merge.rb +34 -0
  37. data/lib/icss/receiver_model/validations.rb +31 -0
  38. data/lib/icss/serialization.rb +51 -0
  39. data/lib/icss/serialization/zaml.rb +443 -0
  40. data/lib/icss/type.rb +148 -501
  41. data/lib/icss/type/base_type.rb +0 -0
  42. data/lib/icss/type/named_type.rb +184 -0
  43. data/lib/icss/type/record_field.rb +77 -0
  44. data/lib/icss/type/record_model.rb +49 -0
  45. data/lib/icss/type/record_schema.rb +54 -0
  46. data/lib/icss/type/record_type.rb +325 -0
  47. data/lib/icss/type/simple_types.rb +72 -0
  48. data/lib/icss/type/structured_schema.rb +288 -0
  49. data/lib/icss/type/type_factory.rb +144 -0
  50. data/lib/icss/type/union_schema.rb +41 -0
  51. data/lib/icss/view_helper.rb +56 -19
  52. data/notes/named_array.md +32 -0
  53. data/notes/on_include_vs_extend_etc.rb +176 -0
  54. data/notes/technical_details.md +278 -0
  55. data/spec/core_types_spec.rb +119 -0
  56. data/spec/fixtures/zaml_complex_hash.yaml +35 -0
  57. data/spec/icss_spec.rb +86 -23
  58. data/spec/message/message_sample_spec.rb +4 -0
  59. data/spec/message_spec.rb +139 -0
  60. data/spec/protocol/license_spec.rb +67 -0
  61. data/spec/protocol/protocol_catalog_spec.rb +48 -0
  62. data/spec/protocol/protocol_validations_spec.rb +176 -0
  63. data/spec/protocol/source_spec.rb +65 -0
  64. data/spec/protocol_spec.rb +91 -37
  65. data/spec/receiver_model_spec.rb +111 -0
  66. data/spec/serialization/zaml_spec.rb +81 -0
  67. data/spec/serialization/zaml_test.rb +473 -0
  68. data/spec/serialization_spec.rb +63 -0
  69. data/spec/spec_helper.rb +24 -7
  70. data/spec/support/icss_test_helper.rb +67 -0
  71. data/spec/support/load_example_protocols.rb +17 -0
  72. data/spec/type/base_type_spec.rb +0 -0
  73. data/spec/type/named_type_spec.rb +75 -0
  74. data/spec/type/record_field_spec.rb +44 -0
  75. data/spec/type/record_model_spec.rb +206 -0
  76. data/spec/type/record_schema_spec.rb +161 -0
  77. data/spec/type/record_type_spec.rb +155 -0
  78. data/spec/type/simple_types_spec.rb +121 -0
  79. data/spec/type/structured_schema_spec.rb +300 -0
  80. data/spec/type/type_catalog_spec.rb +44 -0
  81. data/spec/type/type_factory_spec.rb +93 -0
  82. data/spec/type/union_schema_spec.rb +0 -0
  83. data/spec/type_spec.rb +63 -0
  84. metadata +205 -144
  85. data/CHANGELOG.textile +0 -9
  86. data/Gemfile.lock +0 -40
  87. data/README.textile +0 -29
  88. data/lib/icss/brevity.rb +0 -136
  89. data/lib/icss/code_asset.rb +0 -16
  90. data/lib/icss/core_ext.rb +0 -9
  91. data/lib/icss/data_asset.rb +0 -22
  92. data/lib/icss/old.rb +0 -96
  93. data/lib/icss/protocol_set.rb +0 -48
  94. data/lib/icss/sample_message_call.rb +0 -142
  95. data/lib/icss/target.rb +0 -72
  96. data/lib/icss/type/factory.rb +0 -196
  97. data/lib/icss/validations.rb +0 -16
  98. data/spec/validations_spec.rb +0 -171
@@ -0,0 +1,72 @@
1
+ module Icss
2
+ module Meta
3
+ module PrimitiveSchema
4
+ def to_schema() fullname ; end
5
+ def doc() "" end
6
+ def doc=(str)
7
+ singleton_class.class_eval do
8
+ remove_possible_method(:doc)
9
+ define_method(:doc){ str }
10
+ end
11
+ end
12
+ end
13
+
14
+ module NilClassSchema ; include PrimitiveSchema ; def fullname() :null ; end ; def receive(val=nil) raise(ArgumentError, "#{self} must be initialized with nil, but [#{val}] was given") unless val.nil? ; nil ; end ; end
15
+ module BooleanSchema ; include PrimitiveSchema ; def fullname() :boolean ; end ; def receive(val=nil) case when val.nil? then nil when val.to_s.strip.blank? then false else val.to_s.strip != "false" end ; end ; end
16
+ module IntegerSchema ; include PrimitiveSchema ; def fullname() :int ; end ; def receive(val=nil) val.blank? ? nil : val.to_i ; end ; end
17
+ module LongSchema ; include PrimitiveSchema ; def fullname() :long ; end ; end
18
+ module FloatSchema ; include PrimitiveSchema ; def fullname() :float ; end ; def receive(val=nil) val.blank? ? nil : val.to_f ; end ; end
19
+ module DoubleSchema ; include PrimitiveSchema ; def fullname() :double ; end ; end
20
+ module StringSchema ; include PrimitiveSchema ; def fullname() :string ; end ; def receive(val=nil) self.new(val.to_s) ; end ; end
21
+ module BinarySchema ; include PrimitiveSchema ; def fullname() :bytes ; end ; end
22
+ #
23
+ module NumericSchema ; include PrimitiveSchema ; def fullname() :numeric ; end ; def receive(val=nil) val.blank? ? nil : val.to_f ; end ; end
24
+ module SymbolSchema ; include PrimitiveSchema ; def fullname() :symbol ; end ; def receive(val=nil) val.blank? ? nil : val.to_sym ; end ; end
25
+ module TimeSchema ; include PrimitiveSchema ; def fullname() :time ; end ; def receive(val=nil) val.blank? ? nil : self.parse(val.to_s).utc rescue nil ; end ; end
26
+ module RegexpSchema ; include PrimitiveSchema ; def fullname() :regexp ; end ; def receive(val=nil) val.blank? ? nil : Regexp.new(val.to_s) ; end ; end
27
+ end
28
+
29
+ class ::NilClass ; self.extend ::Icss::Meta::NilClassSchema ; end
30
+ class ::Boolean < ::BasicObject ; self.extend ::Icss::Meta::BooleanSchema ; end
31
+ class ::Integer ; self.extend ::Icss::Meta::IntegerSchema ; end
32
+ class ::Long < ::Integer ; self.extend ::Icss::Meta::LongSchema ; end
33
+ class ::Float ; self.extend ::Icss::Meta::FloatSchema ; end
34
+ class ::Double < ::Float ; self.extend ::Icss::Meta::DoubleSchema ; end
35
+ class ::String ; self.extend ::Icss::Meta::StringSchema ; end
36
+ class ::Binary < ::String ; self.extend ::Icss::Meta::BinarySchema ; end
37
+ #
38
+ class ::Numeric ; self.extend ::Icss::Meta::NumericSchema ; end
39
+ class ::Symbol ; self.extend ::Icss::Meta::SymbolSchema ; end
40
+ class ::Time ; self.extend ::Icss::Meta::TimeSchema ; end
41
+ class ::Regexp ; self.extend ::Icss::Meta::RegexpSchema ; end
42
+
43
+ end
44
+
45
+ class ::Boolean < BasicObject
46
+ attr_accessor :val
47
+ def initialize(val=nil)
48
+ self.val = val
49
+ end
50
+ def self.methods() ::TrueClass.methods | ::Icss::Meta::BooleanSchema.instance_methods ; end
51
+ def method_missing(meth, *args)
52
+ val.send(meth, *args)
53
+ end
54
+ def respond_to?(meth)
55
+ super(meth) || val.respond_to?(meth)
56
+ end
57
+ def inspect()
58
+ "<Boolean #{val.inspect}>"
59
+ end
60
+ def class() ::Boolean ; end
61
+ def !() (! val) ; end
62
+ def ==(other_val) val == other_val ; end
63
+ def !=(other_val) val != other_val ; end
64
+ def try_dup() ::Boolean.new(val) ; end
65
+ end
66
+
67
+ # Datamapper also defines:
68
+ #
69
+ # Apikey BCryptHash URI UUID Slug CommaSeparatedList Csv IpAddress Json Yaml Enum Flag Discriminator
70
+ #
71
+ # maybe someday we will too...
72
+
@@ -0,0 +1,288 @@
1
+ module Icss
2
+ module Meta
3
+
4
+ class NamedSchema
5
+ include Icss::Meta::RecordModel
6
+ include Icss::ReceiverModel::ActsAsHash
7
+ include Gorillib::Hashlike
8
+ field :fullname, String, :required => true
9
+ field :is_core, Boolean, :default => false
10
+ attr_accessor :is_core
11
+
12
+ rcvr_alias :name, :fullname
13
+ #
14
+ class_attribute :klass_metatypes ; self.klass_metatypes = []
15
+ class_attribute :parent_metamodels ; self.parent_metamodels = []
16
+
17
+ after_receive(:verify_name) do |hsh|
18
+ warn "** Missing name for #{self}" unless self.fullname.present?
19
+ end
20
+
21
+ after_receive(:register) do |hsh|
22
+ begin
23
+ Icss::Meta::Type.register(self.model_klass)
24
+ rescue
25
+ # If all after_receivers haven't been called, model_klass may error.
26
+ # Adding another after_receiver here, adds it to the end of the list
27
+ self.class.after_receive(:register_again) do
28
+ Icss::Meta::Type.register(self.model_klass)
29
+ end
30
+ end
31
+ end
32
+
33
+ def is_core?
34
+ !!is_core
35
+ end
36
+
37
+ def attrs_to_inscribe
38
+ self.class.field_names
39
+ end
40
+
41
+ def model_klass
42
+ return @model_klass if @model_klass
43
+ @model_klass = Icss::Meta::NamedType.get_model_klass(fullname, parent_klass||Object)
44
+ model_type = @model_klass.singleton_class
45
+ # inscribe attributes
46
+ attrs_to_inscribe.each do |attr|
47
+ val = self.send(attr)
48
+ model_type.class_eval{ define_method(attr){ val } }
49
+ end
50
+ schema_writer = self
51
+ model_type.class_eval{ define_method(:_schema){ schema_writer } }
52
+ # module inclusions
53
+ parent_metamodels.each do |parent_metamodel|
54
+ @model_klass.class_eval{ include parent_metamodel }
55
+ end
56
+ klass_metatypes.each{|mt| @model_klass.extend(mt) }
57
+ @model_klass.metamodel if @model_klass.respond_to?(:metamodel)
58
+ @model_klass
59
+ end
60
+ #
61
+ def self.receive(schema)
62
+ super(schema).model_klass
63
+ end
64
+ def to_hash
65
+ hsh = super
66
+ hsh[:type] = type
67
+ hsh[:name] = hsh.delete(:fullname)
68
+ hsh.delete(:is_core)
69
+ hsh
70
+ end
71
+ end
72
+
73
+ class StructuredSchema < NamedSchema
74
+ class_attribute :parent_klass
75
+ self.klass_metatypes = [::Icss::Meta::NamedType]
76
+ end
77
+
78
+ # An array of objects with a specified type.
79
+ module ArrayType
80
+ def receive(raw)
81
+ return nil if raw.nil? || (raw == "")
82
+ self.new( raw.map{|raw_item| raw_item.is_a?(items) ? raw_item : items.receive(raw_item) } )
83
+ end
84
+ def to_schema() _schema.to_hash end
85
+ end
86
+ module ArrayModel
87
+ def to_wire(options={})
88
+ map{|item| item.respond_to?(:to_wire) ? item.to_wire(options) : item }
89
+ end
90
+ end
91
+
92
+ # A hash of objects with a specified type.
93
+ module HashType
94
+ def receive(raw)
95
+ return nil if raw.nil? || (raw == "")
96
+ obj = self.new
97
+ raw.each{|rk,rv| obj[rk] = (rv.is_a?(values) ? rv : values.receive(rv)) }
98
+ obj
99
+ end
100
+ def to_schema() _schema.to_hash end
101
+ end
102
+
103
+ # A symbol from a pre-chosen set
104
+ module EnumType
105
+ def receive(raw)
106
+ obj = super(raw) or return
107
+ unless self.symbols.include?(obj) then raise ArgumentError, "Cannot receive #{raw}: must be one of #{symbols[0..2].join(',')}#{symbols.length > 3 ? ",..." : ""}" ; end
108
+ obj
109
+ end
110
+ def to_schema() _schema.to_hash end
111
+ end
112
+
113
+ # A Fixed-length buffer. The class size specifies the number of bytes per value (required).
114
+ module FixedType
115
+ # Error thrown when a FixedType is given too few/many bytes
116
+ class FixedValueWrongSizeError < ArgumentError ; end
117
+ # accept like a string but enforce (violently) the length constraint
118
+ def receive(raw)
119
+ obj = super(raw) ; return nil if obj.blank?
120
+ unless obj.bytesize == self.size then raise FixedValueWrongSizeError.new("Wrong size for a fixed-length type #{self.fullname}: got #{obj.bytesize}, not #{self.size}") ; end
121
+ obj
122
+ end
123
+ def to_schema() _schema.to_hash end
124
+ end
125
+
126
+ # -------------------------------------------------------------------------
127
+ #
128
+ # Container Types (array, map and union)
129
+ #
130
+
131
+ #
132
+ # ArraySchema describes an Array type (as opposed to ArrayType, which
133
+ # implements it)
134
+ #
135
+ # Arrays use the type name "array" and support a single attribute:
136
+ #
137
+ # * items: the schema of the array's items.
138
+ #
139
+ # @example, an array of strings is declared with:
140
+ #
141
+ # {"type": "array", "items": "string"}
142
+ #
143
+ class ArraySchema < ::Icss::Meta::StructuredSchema
144
+ self.parent_klass = Array
145
+ self.klass_metatypes += [::Icss::Meta::ArrayType]
146
+ self.parent_metamodels += [::Icss::Meta::ArrayModel]
147
+ field :items, Icss::Meta::TypeFactory, :required => true
148
+ #
149
+ after_receive(:register){ true } # don't register
150
+ def fullname
151
+ return @fullname if @fullname
152
+ slug = (Type.klassname_for(items) || object_id.to_s).gsub(/^:*Icss:+/, '').gsub(/:+/, 'Dot')
153
+ @fullname = "ArrayOf#{slug}"
154
+ end
155
+ #
156
+ def self.receive(hsh)
157
+ hsh.symbolize_keys!
158
+ warn "Suspicious key :values - array schema takes :items (#{hsh})" if hsh.has_key?(:values)
159
+ val = super(hsh)
160
+ raise ArgumentError, "Items Factory is no good: #{hsh} - #{val._schema.to_hash}" if val.items.blank?
161
+ val
162
+ end
163
+ def to_hash
164
+ { :type => :array, :items => Type.schema_for(items) }
165
+ end
166
+ def type() :array ; end
167
+ end
168
+
169
+ #
170
+ # HashSchema describes an Avro Map type (which corresponds to a Ruby
171
+ # Hash).
172
+ #
173
+ # Hashes use the type name "hash" (or "map") and support one attribute:
174
+ #
175
+ # * values: the schema of the map's values. Avro Map keys are assumed to be strings.
176
+ #
177
+ # @example, a map from string to long is declared with:
178
+ #
179
+ # {"type": "map", "values": "long"}
180
+ #
181
+ class HashSchema < ::Icss::Meta::StructuredSchema
182
+ self.parent_klass = Hash
183
+ self.klass_metatypes += [::Icss::Meta::HashType]
184
+ field :values, Icss::Meta::TypeFactory, :required => true
185
+ #
186
+ after_receive(:register){ true } # don't register
187
+ def fullname
188
+ return @fullname if @fullname
189
+ slug = (Type.klassname_for(values) || object_id.to_s).gsub(/^:*Icss:+/, '').gsub(/:+/, 'Dot')
190
+ self.fullname = "HashOf#{slug}"
191
+ end
192
+ #
193
+ def self.receive(hsh)
194
+ hsh.symbolize_keys!
195
+ warn "Suspicious key :items - hash schema takes :values (#{hsh})" if hsh.has_key?(:items)
196
+ val = super(hsh)
197
+ raise ArgumentError, "Value Factory is no good: #{hsh} - #{val._schema}" if val.values.blank?
198
+ val
199
+ end
200
+ def to_hash
201
+ { :type => :map, :values => Type.schema_for(values) }
202
+ end
203
+ def type() :map ; end
204
+ end # HashSchema
205
+
206
+ #
207
+ # An EnumSchema escribes an Enum type.
208
+ #
209
+ # Enums use the type name "enum" and support the following attributes:
210
+ #
211
+ # name: a string providing the name of the enum (required).
212
+ # namespace: a string that qualifies the name;
213
+ # doc: a string providing documentation to the user of this schema (optional).
214
+ # symbols: an array, listing symbols, as strings or ruby symbols (required). All
215
+ # symbols in an enum must be unique; duplicates are prohibited.
216
+ #
217
+ # For example, playing card suits might be defined with:
218
+ #
219
+ # { "type": "enum",
220
+ # "name": "Suit",
221
+ # "symbols" : ["SPADES", "HEARTS", "DIAMONDS", "CLUBS"]
222
+ # }
223
+ #
224
+ class EnumSchema < ::Icss::Meta::StructuredSchema
225
+ self.parent_klass = Symbol
226
+ self.klass_metatypes += [::Icss::Meta::EnumType]
227
+ field :symbols, Array, :items => Symbol, :required => true
228
+ def type() :enum ; end
229
+ end # EnumSchema
230
+
231
+ #
232
+ # Description of an Fixed type.
233
+ #
234
+ # Fixed uses the type name "fixed" and supports the attributes:
235
+ #
236
+ # * name: a string naming this fixed (required).
237
+ # * namespace, a string that qualifies the name;
238
+ # * size: an integer, specifying the number of bytes per value (required).
239
+ #
240
+ # For example, 16-byte quantity may be declared with:
241
+ #
242
+ # {"type": "fixed", "size": 16, "name": "md5"}
243
+ #
244
+ class FixedSchema < ::Icss::Meta::StructuredSchema
245
+ self.parent_klass = String
246
+ self.klass_metatypes += [::Icss::Meta::FixedType]
247
+ field :size, Integer, :validates => { :numericality => { :greater_than => 0 }}
248
+ def type() :fixed ; end
249
+ end # FixedSchema
250
+
251
+ #
252
+ # Description of a simple type (derived from one of the base classes)
253
+ #
254
+ # Simple uses the type name "simple" and supports the attributes:
255
+ #
256
+ # * name: a string naming this fixed (required).
257
+ # * namespace, a string that qualifies the name;
258
+ #
259
+ class SimpleSchema < ::Icss::Meta::NamedSchema
260
+ field :basename, Symbol, :required => true
261
+ field :namespace, String
262
+ field :is_a, Array, :default => [], :items => Icss::Meta::TypeFactory
263
+ field :doc, String, :required => true
264
+ rcvr_alias :name, :basename
265
+ self.klass_metatypes = [::Icss::Meta::NamedType]
266
+
267
+ def basename=(s)
268
+ segs = s.to_s.split(/\./)
269
+ @basename = segs.pop.to_sym
270
+ @namespace = segs.join('.').to_s if segs.present?
271
+ end
272
+ def receive_basename(s) self.basename = s.to_sym ; end
273
+
274
+ def fullname
275
+ [namespace, basename].compact_blank.join('.')
276
+ end
277
+
278
+ def type() :simple ; end
279
+ #
280
+ def parent_klass() is_a.first ; end
281
+ def parent_metamodels()
282
+ return [] if is_a.length <= 1
283
+ is_a[1 .. -1].map{|pk| pk.metamodel if pk.respond_to?(:metamodel) }.compact
284
+ end
285
+ end # SimpleSchema
286
+
287
+ end
288
+ end
@@ -0,0 +1,144 @@
1
+ module Icss
2
+ module Meta
3
+
4
+ # Receives any object just as given.
5
+ #
6
+ # @example
7
+ # # receive_foo accepts the item just as given
8
+ # field :foo, Icss::Meta::IdenticalFactory
9
+ #
10
+ class IdenticalFactory
11
+ def self.receive(obj)
12
+ obj
13
+ end
14
+ end
15
+
16
+ class IdenticalHashFactory
17
+ def self.to_schema() { :type => 'map' } ; end
18
+ def self.receive(obj)
19
+ unless obj.nil? || obj.respond_to?(:each_pair) then raise(ArgumentError, "Must supply a hashlike value, got #{obj.to_s[0..100]}") ; end
20
+ obj
21
+ end
22
+ end
23
+
24
+ class IdenticalArrayFactory
25
+ def self.to_schema() { :type => 'array' } ; end
26
+ def self.receive(obj)
27
+ unless obj.nil? || obj.respond_to?(:each) then raise(ArgumentError, "Must supply an arraylike value, got #{obj.to_s[0..100]}") ; end
28
+ obj
29
+ end
30
+ end
31
+
32
+ module TypeFactory
33
+
34
+ ::Icss::FACTORY_TYPES.merge!({
35
+ Icss::Meta::TypeFactory => Icss::Meta::TypeFactory,
36
+ Object => Icss::Meta::IdenticalFactory,
37
+ Icss::Meta::IdenticalFactory => Icss::Meta::IdenticalFactory,
38
+ })
39
+
40
+ #
41
+ # A Schema is represented by one of:
42
+ #
43
+ # * A symbol or string, naming a defined type.
44
+ # * A class that responds to +.receive+, returned as itself
45
+ # * A hash (respond_to?(:each_pair), of the form:
46
+ # {"type": "typename" ...attributes...}
47
+ # where typename is either a simple or derived type name, as defined
48
+ # in the Icss::Type class
49
+ # * An array, representing a union of embedded types.
50
+ #
51
+ def self.receive schema
52
+ flavor, klass = classify_schema_declaration(schema)
53
+ # p ['tfr', __FILE__, flavor, klass, schema]
54
+ case flavor
55
+ when :simple then return klass
56
+ when :factory then return klass
57
+ when :is_type then return klass
58
+ when :structured_schema then return receive_structured_schema(klass, schema)
59
+ when :union_schema then return receive_union_schema(klass, schema)
60
+ when :named_type then return receive_named_type(klass, schema)
61
+ else
62
+ end
63
+ end
64
+
65
+ #
66
+ # A Schema is represented by one of:
67
+ #
68
+ # * A symbol or string, naming a defined type.
69
+ # * A class that responds to +.receive+, returned as itself
70
+ # * A hash (respond_to?(:each_pair), of the form:
71
+ # {"type": "typeName" ...attributes...}
72
+ # where typeName is either a simple or derived type name, as defined
73
+ # in the Icss::Type class
74
+ # * An array, representing a union of embedded types.
75
+ #
76
+ #
77
+ def self.classify_schema_declaration(schema)
78
+ if schema.respond_to?(:each_pair)
79
+ schema.symbolize_keys!
80
+ type = schema[:type]
81
+ else type = schema
82
+ end
83
+ type = type.to_sym if type.respond_to?(:to_sym)
84
+ # p ['clfy', __FILE__, schema, type]
85
+
86
+ # FIXME -- make this match the preamble comment
87
+
88
+ if type.is_a?(Module) && type < NamedType then return [:is_type, type]
89
+ elsif ::Icss::SIMPLE_TYPES.include?(type) then return [:simple, SIMPLE_TYPES[type]]
90
+ elsif (type == Array) && schema[:items].blank? then return [:factory, IdenticalArrayFactory]
91
+ elsif (type == Hash) && schema[:values].blank? then return [:factory, IdenticalHashFactory]
92
+ elsif ::Icss::FACTORY_TYPES.include?(type) then return [:factory, FACTORY_TYPES[type]]
93
+ elsif ::Icss::STRUCTURED_SCHEMAS.include?(type) then return [:structured_schema, STRUCTURED_SCHEMAS[type]]
94
+ elsif (type == :base) then return [:is_type, schema[:name].camelize.constantize]
95
+ elsif (type == :union) || type.is_a?(Array) then return [:union_schema, Icss::Meta::UnionSchema]
96
+ elsif type.is_a?(Symbol) && type.to_s =~ /^[\w\.\:]+/ then return [:named_type, type]
97
+ elsif type.is_a?(Class) || type.is_a?(Module) then return [:is_type, type]
98
+ elsif type.respond_to?(:each_pair) then return [:is_type, receive(type)]
99
+ else raise ArgumentError, %Q{Can not classify #{schema.inspect}: should be the handle for a named type; one of #{SIMPLE_TYPES.keys.join(',')}; a schema of the form {"type": "typename" ...attributes....}; or an array (representing a union type).}
100
+ end
101
+ end
102
+
103
+ def self.with_namespace(def_ns)
104
+ old_def_ns = @default_namespace
105
+ @default_namespace = def_ns
106
+ ret = yield
107
+ @default_namespace = old_def_ns
108
+ ret
109
+ end
110
+
111
+ def self.namespaced_name(nm)
112
+ nm = nm.to_s
113
+ return nm if (nm == 'thing') || (nm =~ /[\.\/]/)
114
+ [@default_namespace, nm].compact.join('.')
115
+ end
116
+
117
+ protected
118
+
119
+ def self.receive_named_type(type_name, schema)
120
+ ns_name = namespaced_name(type_name)
121
+ klass_name = Icss::Meta::Type.klassname_for(ns_name.to_sym)
122
+ # p ['rnt', type_name, schema, ns_name, klass_name]
123
+ begin
124
+ klass_name.constantize
125
+ rescue NameError => e
126
+ # Log.debug "auto loading core type #{ns_name} - #{schema}" if defined?(Log)
127
+ Icss::Meta::Type.find(ns_name)
128
+ end
129
+ end
130
+
131
+ def self.receive_structured_schema(schema_writer, schema)
132
+ if (schema[:name].to_s !~ /[\.\/]/) && @default_namespace && (schema[:name].to_s != 'thing')
133
+ schema[:namespace] ||= @default_namespace
134
+ end
135
+ schema_writer.receive(schema)
136
+ end
137
+
138
+ def self.receive_union_schema(schema_writer, schema)
139
+ schema_writer.receive(schema)
140
+ end
141
+
142
+ end
143
+ end
144
+ end