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.
- data/.watchr +35 -3
- data/CHANGELOG.md +38 -0
- data/Gemfile +19 -14
- data/README.md +296 -0
- data/Rakefile +2 -6
- data/TODO.md +13 -0
- data/VERSION +1 -1
- data/examples/avro_examples/complicated.icss.yaml +14 -13
- data/examples/bnc.icss.yaml +70 -0
- data/examples/chronic.icss.yaml +3 -3
- data/examples/license.icss.yaml +7 -0
- data/examples/source1.icss.yaml +4 -0
- data/examples/source2.icss.yaml +4 -0
- data/examples/test_icss.yaml +67 -0
- data/icss.gemspec +103 -43
- data/lib/icss.rb +37 -15
- data/lib/icss/core_types.rb +19 -0
- data/lib/icss/error.rb +4 -0
- data/{init.rb → lib/icss/init.rb} +0 -0
- data/lib/icss/message.rb +124 -66
- data/lib/icss/message/message_sample.rb +144 -0
- data/lib/icss/protocol.rb +184 -131
- data/lib/icss/protocol/code_asset.rb +18 -0
- data/lib/icss/protocol/data_asset.rb +23 -0
- data/lib/icss/protocol/license.rb +41 -0
- data/lib/icss/protocol/source.rb +37 -0
- data/lib/icss/protocol/target.rb +68 -0
- data/lib/icss/receiver_model.rb +24 -0
- data/lib/icss/receiver_model/active_model_shim.rb +36 -0
- data/lib/icss/receiver_model/acts_as_catalog.rb +170 -0
- data/lib/icss/receiver_model/acts_as_hash.rb +177 -0
- data/lib/icss/receiver_model/acts_as_loadable.rb +47 -0
- data/lib/icss/receiver_model/acts_as_tuple.rb +100 -0
- data/lib/icss/receiver_model/locale/en.yml +27 -0
- data/lib/icss/receiver_model/to_geo_json.rb +19 -0
- data/lib/icss/receiver_model/tree_merge.rb +34 -0
- data/lib/icss/receiver_model/validations.rb +31 -0
- data/lib/icss/serialization.rb +51 -0
- data/lib/icss/serialization/zaml.rb +443 -0
- data/lib/icss/type.rb +148 -501
- data/lib/icss/type/base_type.rb +0 -0
- data/lib/icss/type/named_type.rb +184 -0
- data/lib/icss/type/record_field.rb +77 -0
- data/lib/icss/type/record_model.rb +49 -0
- data/lib/icss/type/record_schema.rb +54 -0
- data/lib/icss/type/record_type.rb +325 -0
- data/lib/icss/type/simple_types.rb +72 -0
- data/lib/icss/type/structured_schema.rb +288 -0
- data/lib/icss/type/type_factory.rb +144 -0
- data/lib/icss/type/union_schema.rb +41 -0
- data/lib/icss/view_helper.rb +56 -19
- data/notes/named_array.md +32 -0
- data/notes/on_include_vs_extend_etc.rb +176 -0
- data/notes/technical_details.md +278 -0
- data/spec/core_types_spec.rb +119 -0
- data/spec/fixtures/zaml_complex_hash.yaml +35 -0
- data/spec/icss_spec.rb +86 -23
- data/spec/message/message_sample_spec.rb +4 -0
- data/spec/message_spec.rb +139 -0
- data/spec/protocol/license_spec.rb +67 -0
- data/spec/protocol/protocol_catalog_spec.rb +48 -0
- data/spec/protocol/protocol_validations_spec.rb +176 -0
- data/spec/protocol/source_spec.rb +65 -0
- data/spec/protocol_spec.rb +91 -37
- data/spec/receiver_model_spec.rb +111 -0
- data/spec/serialization/zaml_spec.rb +81 -0
- data/spec/serialization/zaml_test.rb +473 -0
- data/spec/serialization_spec.rb +63 -0
- data/spec/spec_helper.rb +24 -7
- data/spec/support/icss_test_helper.rb +67 -0
- data/spec/support/load_example_protocols.rb +17 -0
- data/spec/type/base_type_spec.rb +0 -0
- data/spec/type/named_type_spec.rb +75 -0
- data/spec/type/record_field_spec.rb +44 -0
- data/spec/type/record_model_spec.rb +206 -0
- data/spec/type/record_schema_spec.rb +161 -0
- data/spec/type/record_type_spec.rb +155 -0
- data/spec/type/simple_types_spec.rb +121 -0
- data/spec/type/structured_schema_spec.rb +300 -0
- data/spec/type/type_catalog_spec.rb +44 -0
- data/spec/type/type_factory_spec.rb +93 -0
- data/spec/type/union_schema_spec.rb +0 -0
- data/spec/type_spec.rb +63 -0
- metadata +205 -144
- data/CHANGELOG.textile +0 -9
- data/Gemfile.lock +0 -40
- data/README.textile +0 -29
- data/lib/icss/brevity.rb +0 -136
- data/lib/icss/code_asset.rb +0 -16
- data/lib/icss/core_ext.rb +0 -9
- data/lib/icss/data_asset.rb +0 -22
- data/lib/icss/old.rb +0 -96
- data/lib/icss/protocol_set.rb +0 -48
- data/lib/icss/sample_message_call.rb +0 -142
- data/lib/icss/target.rb +0 -72
- data/lib/icss/type/factory.rb +0 -196
- data/lib/icss/validations.rb +0 -16
- 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
|