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
data/lib/icss/type.rb
CHANGED
@@ -1,521 +1,168 @@
|
|
1
|
-
module Icss
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
# where typeName is either a primitive or derived type name, as defined
|
11
|
-
# in the Icss::Type class
|
12
|
-
# * A JSON array, representing a union of embedded types.
|
13
|
-
#
|
14
|
-
#
|
15
|
-
class Type
|
16
|
-
include Receiver
|
17
|
-
rcvr_accessor :name, String
|
18
|
-
rcvr_accessor :doc, String
|
19
|
-
# Schema factory
|
20
|
-
rcvr_accessor :ruby_klass, Object
|
21
|
-
rcvr_accessor :pig_name, String
|
22
|
-
rcvr_accessor :mysql_name, String
|
23
|
-
|
24
|
-
#
|
25
|
-
# Factory methods
|
26
|
-
#
|
27
|
-
|
28
|
-
# Registry for synthesized types (eg the result of a type record definition)
|
29
|
-
Icss::Type::DERIVED_TYPES = {} unless defined?(Icss::Type::DERIVED_TYPES)
|
30
|
-
|
31
|
-
# VALID_TYPES, PRIMITIVE_TYPES, etc are way down below (the klasses need to
|
32
|
-
# be defined first)
|
33
|
-
|
34
|
-
#
|
35
|
-
def self.find type_name
|
36
|
-
if type_name.to_s.include?('.')
|
37
|
-
warn "crap. can't properly do namespaced types yet."
|
38
|
-
type_name = type_name.to_s.gsub(/(.*)\./, "")
|
1
|
+
module Icss
|
2
|
+
module Meta
|
3
|
+
module Type
|
4
|
+
include Icss::ReceiverModel::ActsAsCatalog
|
5
|
+
def self.catalog_sections
|
6
|
+
::Icss::Meta::Protocol.catalog_sections
|
7
|
+
end
|
8
|
+
def self.receive(hsh)
|
9
|
+
::Icss::Meta::Protocol.receive(hsh)
|
39
10
|
end
|
40
|
-
Icss::Type::VALID_TYPES[type_name.to_sym] || Icss::Type::DERIVED_TYPES[type_name.to_sym]
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.primitive? name
|
44
|
-
PRIMITIVE_TYPES.include?(name.to_sym)
|
45
|
-
end
|
46
|
-
def primitive?
|
47
|
-
false
|
48
|
-
end
|
49
|
-
|
50
|
-
def title
|
51
|
-
self.name
|
52
|
-
end
|
53
|
-
|
54
|
-
#
|
55
|
-
# Schema Translation
|
56
|
-
#
|
57
|
-
def self.pig_name
|
58
|
-
"undefined_#{self.to_s.underscore}"
|
59
|
-
end
|
60
|
-
#
|
61
|
-
# Conversion
|
62
|
-
#
|
63
|
-
|
64
|
-
def to_hash()
|
65
|
-
{:name => name, :doc => doc }.reject{|k,v| v.nil? }
|
66
11
|
end
|
67
|
-
# This will cause funny errors when it is an element of something that's to_json'ed
|
68
|
-
def to_json() to_hash.to_json ; end
|
69
12
|
end
|
70
13
|
|
71
|
-
# ---------------------------------------------------------------------------
|
72
|
-
#
|
73
|
-
# Primitive Types
|
74
14
|
#
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
15
|
+
# Predefining the namespaces here makes inclusion-order less brittle.
|
16
|
+
#
|
17
|
+
|
18
|
+
# full definitions in type/simple_types.rb
|
19
|
+
class ::Boolean < ::BasicObject ; end
|
20
|
+
class ::Long < ::Integer ; end
|
21
|
+
class ::Double < ::Float ; end
|
22
|
+
class ::Binary < ::String ; end
|
23
|
+
|
24
|
+
# patron saint of Simple Types (Structured Text)
|
25
|
+
module St ; end
|
26
|
+
# pasture wherein graze MeasurementUnits
|
27
|
+
module Mu ; end
|
28
|
+
# stand in the place where you are
|
29
|
+
module Business ; end
|
30
|
+
#
|
31
|
+
module Culture ; end
|
32
|
+
# we gots the whhole worl innour hans
|
33
|
+
module Encyclopedic ; end
|
34
|
+
# Eventfully, Tom phoned the caterer.
|
35
|
+
module Ev ; end
|
36
|
+
#
|
37
|
+
module Geo ; end
|
38
|
+
# Relatively speaking, this is where links and relations go
|
39
|
+
module Rel ; end
|
40
|
+
# I don't want to sell anything, buy anything, or process anything as a career.
|
41
|
+
# I don't want to sell anything bought or processed, or buy anything sold or processed, or process
|
42
|
+
# anything sold, bought, or processed, or repair anything sold, bought, or processed.
|
43
|
+
# You know, as a career, I don't want to do that.
|
44
|
+
module Prod ; end
|
45
|
+
#
|
46
|
+
module Social ; end
|
47
|
+
# Oh what a tangled web we weave when first we practice to receive
|
48
|
+
module Web ; end
|
49
|
+
# Raw records, for use by data mungers
|
50
|
+
module Raw ; end
|
51
|
+
|
52
|
+
# Buffalo Buffalo buffalo Buffalo Buffalo Buffalo buffalow.
|
53
|
+
module Meta
|
54
|
+
# full definitions in type/structured_schema.rb and type/union_schema.rb
|
55
|
+
class NamedSchema ; end
|
56
|
+
class SimpleSchema < NamedSchema ; end
|
57
|
+
class UnionSchema < NamedSchema ; end
|
58
|
+
class RecordSchema < SimpleSchema ; end
|
59
|
+
class ErrorSchema < RecordSchema ; end
|
96
60
|
#
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
61
|
+
class StructuredSchema < NamedSchema ; end
|
62
|
+
class HashSchema < StructuredSchema ; end
|
63
|
+
class ArraySchema < StructuredSchema ; end
|
64
|
+
class FixedSchema < StructuredSchema ; end
|
65
|
+
class EnumSchema < StructuredSchema ; end
|
101
66
|
end
|
102
67
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
# if they contain a dot they are a fullname, if they do not contain a dot, the
|
120
|
-
# namespace is the namespace of the enclosing definition.
|
121
|
-
#
|
122
|
-
# Primitive type names have no namespace and their names may not be defined in
|
123
|
-
# any namespace. A schema may only contain multiple definitions of a fullname
|
124
|
-
# if the definitions are equivalent.
|
125
|
-
#
|
126
|
-
#
|
127
|
-
class NamedType < Type
|
128
|
-
rcvr_accessor :namespace, String
|
129
|
-
attr_accessor :parent
|
130
|
-
# the avro base type name
|
131
|
-
class_attribute :type
|
132
|
-
include Icss::Validations
|
133
|
-
|
134
|
-
# In named types, the namespace and name are determined in one of the following ways:
|
135
|
-
#
|
136
|
-
# * A name and namespace are both specified. For example, one might use
|
137
|
-
# "name": "X", "namespace": "org.foo" to indicate the fullname org.foo.X.
|
138
|
-
#
|
139
|
-
# * A fullname is specified. If the name specified contains a dot, then it is
|
140
|
-
# assumed to be a fullname, and any namespace also specified is ignored. For
|
141
|
-
# example, use "name": "org.foo.X" to indicate the fullname org.foo.X.
|
142
|
-
#
|
143
|
-
# * A name only is specified, i.e., a name that contains no dots. In this case
|
144
|
-
# the namespace is taken from the most tightly enclosing schema or
|
145
|
-
# protocol. For example, if "name": "X" is specified, and this occurs within
|
146
|
-
# a field of the record definition of org.foo.Y, then the fullname is
|
147
|
-
# org.foo.X.
|
148
|
-
#
|
149
|
-
def name= nm
|
150
|
-
if nm.include?('.')
|
151
|
-
split_name = nm.split('.')
|
152
|
-
@use_fullname = true
|
153
|
-
@name = split_name.pop
|
154
|
-
@namespace = split_name.join('.')
|
155
|
-
else
|
156
|
-
@name = nm
|
157
|
-
end
|
158
|
-
::Icss::Type::DERIVED_TYPES[@name.to_sym] = self
|
159
|
-
@name
|
160
|
-
end
|
161
|
-
|
162
|
-
def receive_namespace nmsp
|
163
|
-
# If the namespace is given in the name (using a dotted name string) then
|
164
|
-
# any namespace also specified is ignored.
|
165
|
-
if @namespace then warn "Warning: namespace already set, ignoring" and return ; end
|
166
|
-
@namespace = nmsp
|
167
|
-
end
|
168
|
-
|
169
|
-
def namespace
|
170
|
-
@namespace || (parent ? parent.namespace : "")
|
171
|
-
end
|
172
|
-
|
173
|
-
#
|
174
|
-
# If no explicit namespace is specified, the namespace is taken from the
|
175
|
-
# most tightly enclosing schema or protocol. For example, if "name": "X" is
|
176
|
-
# specified, and this occurs within a field of the record definition of
|
177
|
-
# org.foo.Y, then the fullname is org.foo.X.
|
178
|
-
#
|
179
|
-
def fullname
|
180
|
-
[namespace, name].reject(&:blank?).join('.')
|
181
|
-
end
|
182
|
-
|
183
|
-
def to_hash
|
184
|
-
hsh = super
|
185
|
-
if @use_fullname then hsh[:name] = fullname
|
186
|
-
elsif @namespace then hsh.merge!( :namespace => @namespace ) ; end
|
187
|
-
hsh.merge( :type => self.class.type )
|
188
|
-
end
|
68
|
+
::Icss::SIMPLE_TYPES = {} unless defined?( ::Icss::SIMPLE_TYPES )
|
69
|
+
::Icss::FACTORY_TYPES = {} unless defined?( ::Icss::FACTORY_TYPES )
|
70
|
+
::Icss::STRUCTURED_SCHEMAS = {} unless defined?( ::Icss::STRUCTURED_SCHEMAS )
|
71
|
+
::Icss::UNION_SCHEMAS = {} unless defined?( ::Icss::UNION_SCHEMAS )
|
72
|
+
|
73
|
+
unless defined?(::Icss::AVRO_TYPES)
|
74
|
+
::Icss::AVRO_TYPES = {
|
75
|
+
:null => ::NilClass,
|
76
|
+
:boolean => ::Boolean,
|
77
|
+
:int => ::Integer,
|
78
|
+
:long => ::Long,
|
79
|
+
:float => ::Float,
|
80
|
+
:double => ::Double,
|
81
|
+
:string => ::String,
|
82
|
+
:bytes => ::Binary,
|
83
|
+
}.freeze
|
189
84
|
end
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
85
|
+
::Icss::SIMPLE_TYPES.merge!(::Icss::AVRO_TYPES)
|
86
|
+
|
87
|
+
::Icss::SIMPLE_TYPES.merge!({
|
88
|
+
:binary => ::Binary,
|
89
|
+
:symbol => ::Symbol,
|
90
|
+
:time => ::Time,
|
91
|
+
:integer => ::Integer,
|
92
|
+
:numeric => ::Numeric,
|
93
|
+
:regexp => ::Regexp,
|
94
|
+
})
|
95
|
+
|
96
|
+
::Icss::STRUCTURED_SCHEMAS.merge!({
|
97
|
+
:simple => Icss::Meta::SimpleSchema,
|
98
|
+
:record => Icss::Meta::RecordSchema,
|
99
|
+
:error => Icss::Meta::ErrorSchema,
|
100
|
+
:map => Icss::Meta::HashSchema,
|
101
|
+
:hash => Icss::Meta::HashSchema,
|
102
|
+
Hash => Icss::Meta::HashSchema,
|
103
|
+
:array => Icss::Meta::ArraySchema,
|
104
|
+
Array => Icss::Meta::ArraySchema,
|
105
|
+
:fixed => Icss::Meta::FixedSchema,
|
106
|
+
:enum => Icss::Meta::EnumSchema,
|
107
|
+
})
|
108
|
+
::Icss::UNION_SCHEMAS.merge!({
|
109
|
+
:union => Icss::Meta::UnionSchema,
|
110
|
+
})
|
111
|
+
|
112
|
+
module Meta
|
113
|
+
module Type
|
114
|
+
#:nodoc:
|
115
|
+
NORMAL_NAMED_CONSTANT_RE = /\A[\w\:\.]+\z/ unless defined?(NORMAL_NAMED_CONSTANT_RE)
|
116
|
+
|
117
|
+
# Turns a type name into its dotted (avro-style) name, regardless of its
|
118
|
+
# current form.
|
119
|
+
#
|
120
|
+
# @example
|
121
|
+
# Icss::Meta::Type.fullname_for(Icss::This::That::TheOther) # 'this.that.the_other'
|
122
|
+
# Icss::Meta::Type.fullname_for("Icss::This::That::TheOther") # 'this.that.the_other'
|
123
|
+
# Icss::Meta::Type.fullname_for('this.that.the_other') # 'this.that.the_other'
|
124
|
+
#
|
125
|
+
def self.fullname_for(klass_name)
|
126
|
+
return nil unless klass_name.present? && (klass_name.to_s =~ NORMAL_NAMED_CONSTANT_RE)
|
127
|
+
klass_name.to_s.gsub(/^:*Icss::/, '').underscore.gsub(%r{/},".")
|
220
128
|
end
|
221
|
-
end
|
222
|
-
end
|
223
129
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
# record object RecordType {"a": 1}
|
240
|
-
# enum string Enum "FOO"
|
241
|
-
# array array Array [1]
|
242
|
-
# map object Hash { "a": 1 }
|
243
|
-
# fixed string String "\u00ff"
|
244
|
-
#
|
245
|
-
# * default: a default value for this field, used when reading instances that
|
246
|
-
# lack this field (optional). Permitted values depend on the
|
247
|
-
# field's schema type, according to the table below. Default
|
248
|
-
# values for union fields correspond to the first schema in the
|
249
|
-
# union. Default values for bytes and fixed fields are JSON
|
250
|
-
# strings, where Unicode code points 0-255 are mapped to unsigned
|
251
|
-
# 8-bit byte values 0-255.
|
252
|
-
#
|
253
|
-
# * order: specifies how this field impacts sort ordering of this record
|
254
|
-
# (optional). Valid values are "ascending" (the default),
|
255
|
-
# "descending", or "ignore". For more details on how this is used,
|
256
|
-
# see the the sort order section below.
|
257
|
-
#
|
258
|
-
# * required: raises an error if the field is unset when validate! is called
|
259
|
-
#
|
260
|
-
# See RecordType for examples.
|
261
|
-
#
|
262
|
-
class RecordField
|
263
|
-
include Receiver
|
264
|
-
include Receiver::ActsAsHash
|
265
|
-
rcvr_accessor :name, String, :required => true
|
266
|
-
rcvr_accessor :doc, String
|
267
|
-
attr_accessor :type # work around a bug in ruby 1.8, which has defined (and deprecated) type
|
268
|
-
rcvr_accessor :type, Icss::Type, :required => true
|
269
|
-
rcvr_accessor :default, Object
|
270
|
-
rcvr :order, String
|
271
|
-
rcvr_accessor :required, Boolean
|
272
|
-
|
273
|
-
# is_reference is true if the type is a named reference to a defined type;
|
274
|
-
# false if the type was defined right here in the schema.
|
275
|
-
attr_accessor :is_reference
|
276
|
-
def is_reference?() is_reference ; end
|
277
|
-
|
278
|
-
def receive_type type_info
|
279
|
-
self.is_reference = type_info.is_a?(String) || type_info.is_a?(Symbol)
|
280
|
-
self.type = TypeFactory.receive(type_info)
|
281
|
-
end
|
282
|
-
|
283
|
-
ALLOWED_ORDERS = %w[ascending descending ignore].freeze unless defined?(ALLOWED_ORDERS)
|
284
|
-
def order
|
285
|
-
@order || 'ascending'
|
286
|
-
end
|
287
|
-
def order_direction
|
288
|
-
case order when 'ascending' then 1 when 'descending' then -1 else 0 ; end
|
289
|
-
end
|
290
|
-
# QUESTION: should this be an override of order=, or of receive_order?
|
291
|
-
def order= v
|
292
|
-
raise "'order' may only take the values ascending (the default), descending, or ignore." unless v.nil? || ALLOWED_ORDERS.include?(v)
|
293
|
-
@order = v
|
294
|
-
end
|
295
|
-
|
296
|
-
def record?() type.is_a? Icss::RecordType end
|
297
|
-
def union?() type.is_a? Array end
|
298
|
-
def enum?() type.is_a? Icss::EnumType end
|
299
|
-
|
300
|
-
def to_hash()
|
301
|
-
{ :name => name,
|
302
|
-
:type => expand_type,
|
303
|
-
:default => default,
|
304
|
-
:order => @order,
|
305
|
-
:doc => doc,
|
306
|
-
}.reject{|k,v| v.nil? }
|
307
|
-
end
|
308
|
-
|
309
|
-
def expand_type
|
310
|
-
case
|
311
|
-
when is_reference? && type.respond_to?(:name) then type.name
|
312
|
-
when is_reference? then '(_unspecified_)'
|
313
|
-
when type.is_a?(Array) then type.map{|t| t.to_hash }
|
314
|
-
when type.respond_to?(:to_hash) then type.to_hash
|
315
|
-
else type.to_s
|
130
|
+
# Converts a type name to its ruby (camel-cased) form. Works on class,
|
131
|
+
# name of class, or dotted (avro-style) namespace.name. Names will have
|
132
|
+
# an 'Icss::' prefix.
|
133
|
+
#
|
134
|
+
# @example
|
135
|
+
# Icss::Meta::Type.fullname_for('this.that.the_other') # "Icss::This::That::TheOther"
|
136
|
+
# Icss::Meta::Type.fullname_for(Icss::This::That::TheOther) # "Icss::This::That::TheOther"
|
137
|
+
# Icss::Meta::Type.fullname_for("Icss::This::That::TheOther") # "Icss::This::That::TheOther"
|
138
|
+
#
|
139
|
+
def self.klassname_for(obj)
|
140
|
+
return nil unless obj.present? && (obj.to_s =~ NORMAL_NAMED_CONSTANT_RE)
|
141
|
+
nm = obj.to_s.gsub(/^:*Icss:+/, '').
|
142
|
+
gsub(%r{::},'.').
|
143
|
+
split('.').map(&:camelize).join('::')
|
144
|
+
"::Icss::#{nm}"
|
316
145
|
end
|
317
|
-
end
|
318
|
-
end
|
319
|
-
|
320
|
-
#
|
321
|
-
# Icss/Avro Record type
|
322
|
-
#
|
323
|
-
# Records use the type name "record" and support these attributes:
|
324
|
-
#
|
325
|
-
# * name: a string providing the name of the record (required).
|
326
|
-
# * namespace: a string that qualifies the name;
|
327
|
-
# * doc: a string providing documentation to the user of this schema (optional).
|
328
|
-
# * fields: an array of RecordField's (required).
|
329
|
-
#
|
330
|
-
# For example, a linked-list of 64-bit values may be defined with:
|
331
|
-
#
|
332
|
-
# {
|
333
|
-
# "type": "record",
|
334
|
-
# "name": "LongList",
|
335
|
-
# "fields" : [
|
336
|
-
# {"name": "value", "type": "long"}, // each element has a long
|
337
|
-
# {"name": "next", "type": ["LongList", "null"]} // optional next element
|
338
|
-
# ]
|
339
|
-
# }
|
340
|
-
#
|
341
|
-
class RecordType < NamedType
|
342
|
-
rcvr_accessor :fields, Array, :of => Icss::RecordField, :required => true
|
343
|
-
self.type = :record
|
344
|
-
|
345
|
-
after_receive do |hsh|
|
346
|
-
Icss::Type::DERIVED_TYPES[name.to_sym] = self
|
347
|
-
end
|
348
|
-
|
349
|
-
def to_hash
|
350
|
-
super.merge( :fields => (fields||[]).map{|field| field.to_hash} )
|
351
|
-
end
|
352
|
-
end
|
353
|
-
|
354
|
-
# An error definition is just like a record definition except it uses "error" instead of "record".
|
355
|
-
class ErrorType < RecordType
|
356
|
-
self.type = :error
|
357
|
-
end
|
358
|
-
|
359
|
-
#
|
360
|
-
# Describes an Avro Enum type.
|
361
|
-
#
|
362
|
-
# Enums use the type name "enum" and support the following attributes:
|
363
|
-
#
|
364
|
-
# name: a string providing the name of the enum (required).
|
365
|
-
# namespace: a string that qualifies the name;
|
366
|
-
# doc: a string providing documentation to the user of this schema (optional).
|
367
|
-
# symbols: an array, listing symbols, as strings or ruby symbols (required). All
|
368
|
-
# symbols in an enum must be unique; duplicates are prohibited.
|
369
|
-
#
|
370
|
-
# For example, playing card suits might be defined with:
|
371
|
-
#
|
372
|
-
# { "type": "enum",
|
373
|
-
# "name": "Suit",
|
374
|
-
# "symbols" : ["SPADES", "HEARTS", "DIAMONDS", "CLUBS"]
|
375
|
-
# }
|
376
|
-
#
|
377
|
-
class EnumType < NamedType
|
378
|
-
rcvr_accessor :symbols, Array, :of => String, :required => true
|
379
|
-
self.type = :enum
|
380
|
-
|
381
|
-
def to_hash
|
382
|
-
super.merge( :symbols => symbols )
|
383
|
-
end
|
384
|
-
end
|
385
|
-
|
386
|
-
#
|
387
|
-
# base class for Avro enumerable types (array, map and union)
|
388
|
-
#
|
389
|
-
# (do not confuse with EnumType, which is not an EnumerableType. sigh).
|
390
|
-
#
|
391
|
-
class EnumerableType < Type
|
392
|
-
class_attribute :type
|
393
|
-
class_attribute :ruby_klass
|
394
|
-
def to_hash
|
395
|
-
super.merge( :type => type.to_s )
|
396
|
-
end
|
397
|
-
end
|
398
|
-
|
399
|
-
#
|
400
|
-
# ArrayType describes an Avro Array type.
|
401
|
-
#
|
402
|
-
# Arrays use the type name "array" and support a single attribute:
|
403
|
-
#
|
404
|
-
# * items: the schema of the array's items.
|
405
|
-
#
|
406
|
-
# @example, an array of strings is declared with:
|
407
|
-
#
|
408
|
-
# {"type": "array", "items": "string"}
|
409
|
-
#
|
410
|
-
class ArrayType < EnumerableType
|
411
|
-
# FIXME: is items required? The schema doesn't say so.
|
412
|
-
rcvr_accessor :items, TypeFactory, :required => true
|
413
|
-
self.type = :array
|
414
|
-
self.ruby_klass = Array
|
415
|
-
|
416
|
-
def title
|
417
|
-
"array of #{items.title}"
|
418
|
-
end
|
419
|
-
|
420
|
-
def to_hash
|
421
|
-
super.merge( :items => (items && items.name) )
|
422
|
-
end
|
423
|
-
end
|
424
|
-
|
425
|
-
#
|
426
|
-
# MapType describes an Avro Map type (which corresponds to a Ruby
|
427
|
-
# Hash). HashType is a synonym for MapType.
|
428
|
-
#
|
429
|
-
# Maps use the type name "map" and support one attribute:
|
430
|
-
#
|
431
|
-
# * values: the schema of the map's values. Avro Map keys are assumed to be strings.
|
432
|
-
#
|
433
|
-
# @example, a map from string to long is declared with:
|
434
|
-
#
|
435
|
-
# {"type": "map", "values": "long"}
|
436
|
-
#
|
437
|
-
class MapType < EnumerableType
|
438
|
-
# FIXME: is items required? The schema doesn't say so.
|
439
|
-
rcvr_accessor :values, TypeFactory, :required => true
|
440
|
-
self.type = :map
|
441
|
-
self.ruby_klass = Hash
|
442
146
|
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
#
|
450
|
-
# Describes an Avro Union type.
|
451
|
-
#
|
452
|
-
# Unions are represented using JSON arrays. For example, ["string", "null"]
|
453
|
-
# declares a schema which may be either a string or null.
|
454
|
-
#
|
455
|
-
# Unions may not contain more than one schema with the same type, except for
|
456
|
-
# the named types record, fixed and enum. For example, unions containing two
|
457
|
-
# array types or two map types are not permitted, but two types with different
|
458
|
-
# names are permitted. (Names permit efficient resolution when reading and
|
459
|
-
# writing unions.)
|
460
|
-
#
|
461
|
-
# Unions may not immediately contain other unions.
|
462
|
-
#
|
463
|
-
class UnionType < EnumerableType
|
464
|
-
attr_accessor :available_types
|
465
|
-
attr_accessor :referenced_types
|
466
|
-
self.type = :union
|
467
|
-
|
468
|
-
def receive! type_list
|
469
|
-
self.available_types = type_list.map do |type_info|
|
470
|
-
type = TypeFactory.receive(type_info)
|
471
|
-
(referenced_types||=[]) << type if (type_info.is_a?(String) || type_info.is_a?(Symbol))
|
472
|
-
type
|
147
|
+
def self.schema_for(obj)
|
148
|
+
case
|
149
|
+
when obj.respond_to?(:to_schema) then obj.to_schema
|
150
|
+
when str = fullname_for(obj) then str.to_sym
|
151
|
+
else nil ; end
|
473
152
|
end
|
474
|
-
end
|
475
153
|
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
154
|
+
# true if class is among the defined primitive types:
|
155
|
+
# null boolean integer long float double string binary
|
156
|
+
# and so forth
|
157
|
+
#
|
158
|
+
# note this takes no account of inheritance -- only the types specifically
|
159
|
+
# listed in Icss::SIMPLE_TYPES are simple
|
160
|
+
def self.simple?(tt) ::Icss::SIMPLE_TYPES.has_value?(tt) ; end
|
480
161
|
|
481
|
-
|
482
|
-
# Describes an Avro Fixed type.
|
483
|
-
#
|
484
|
-
# Fixed uses the type name "fixed" and supports the attributes:
|
485
|
-
#
|
486
|
-
# * name: a string naming this fixed (required).
|
487
|
-
# * namespace, a string that qualifies the name;
|
488
|
-
# * size: an integer, specifying the number of bytes per value (required).
|
489
|
-
#
|
490
|
-
# For example, 16-byte quantity may be declared with:
|
491
|
-
#
|
492
|
-
# {"type": "fixed", "size": 16, "name": "md5"}
|
493
|
-
#
|
494
|
-
class FixedType < NamedType
|
495
|
-
rcvr_accessor :size, Integer, :required => true
|
496
|
-
class_attribute :ruby_klass
|
497
|
-
self.type = :fixed
|
498
|
-
self.ruby_klass = String
|
162
|
+
def self.union?(tt) false ; end
|
499
163
|
|
500
|
-
|
501
|
-
super.merge( :size => size )
|
502
|
-
end
|
503
|
-
end
|
164
|
+
def self.record?(tt) false ; end
|
504
165
|
|
505
|
-
|
506
|
-
Icss::Type::NAMED_TYPES = {
|
507
|
-
:fixed => FixedType,
|
508
|
-
:enum => EnumType,
|
509
|
-
:record => RecordType,
|
510
|
-
:error => ErrorType
|
511
|
-
}.freeze unless defined?(Icss::Type::NAMED_TYPES)
|
512
|
-
Icss::Type::ENUMERABLE_TYPES = {
|
513
|
-
:array => ArrayType,
|
514
|
-
:map => MapType,
|
515
|
-
:union => UnionType,
|
516
|
-
# :request => RequestType,
|
517
|
-
}.freeze unless defined?(Icss::Type::ENUMERABLE_TYPES)
|
518
|
-
Icss::Type::VALID_TYPES = (Icss::Type::PRIMITIVE_TYPES.merge(Icss::Type::NAMED_TYPES.merge(Icss::Type::ENUMERABLE_TYPES))).freeze unless defined?(Icss::Type::VALID_TYPES)
|
519
|
-
Icss::Type::VALID_TYPES.each{|n, t| t.name = n if t.is_a?(Icss::Type) }
|
166
|
+
end
|
520
167
|
end
|
521
168
|
end
|