icss 0.1.3 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|