slow_blink 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/ext/slow_blink/ext_schema_parser/parser.c +245 -245
  3. data/lib/slow_blink/annotatable.rb +1 -2
  4. data/lib/slow_blink/annotation.rb +8 -1
  5. data/lib/slow_blink/compact_encoder.rb +1 -0
  6. data/lib/slow_blink/definition.rb +34 -10
  7. data/lib/slow_blink/enumeration.rb +15 -12
  8. data/lib/slow_blink/field.rb +9 -8
  9. data/lib/slow_blink/group.rb +61 -24
  10. data/lib/slow_blink/incremental_annotation.rb +7 -4
  11. data/lib/slow_blink/integer.rb +1 -1
  12. data/{test/tc_model.rb → lib/slow_blink/log.rb} +23 -40
  13. data/lib/slow_blink/message/binary.rb +39 -45
  14. data/lib/slow_blink/message/boolean.rb +25 -33
  15. data/lib/slow_blink/message/date.rb +2 -7
  16. data/lib/slow_blink/message/decimal.rb +1 -1
  17. data/lib/slow_blink/message/enumeration.rb +29 -33
  18. data/lib/slow_blink/message/field.rb +29 -37
  19. data/lib/slow_blink/message/fixed.rb +37 -45
  20. data/lib/slow_blink/message/floating_point.rb +24 -32
  21. data/lib/slow_blink/message/group.rb +172 -187
  22. data/lib/slow_blink/message/integer.rb +83 -132
  23. data/lib/slow_blink/message/model.rb +64 -63
  24. data/lib/slow_blink/message/sequence.rb +40 -48
  25. data/lib/slow_blink/message/string.rb +44 -51
  26. data/lib/slow_blink/message/time.rb +25 -40
  27. data/lib/slow_blink/message/time_of_day.rb +73 -86
  28. data/lib/slow_blink/name_with_id.rb +2 -6
  29. data/lib/slow_blink/namespace.rb +36 -36
  30. data/lib/slow_blink/ref.rb +29 -13
  31. data/lib/slow_blink/schema.rb +26 -10
  32. data/lib/slow_blink/schema_buffer.rb +14 -0
  33. data/lib/slow_blink/sequence.rb +16 -20
  34. data/lib/slow_blink/string.rb +0 -2
  35. data/lib/slow_blink/sym.rb +7 -5
  36. data/lib/slow_blink/type.rb +8 -5
  37. data/lib/slow_blink/version.rb +1 -1
  38. data/test/tc_field.rb +41 -0
  39. data/test/tc_group.rb +11 -0
  40. data/test/tc_model_static_group.rb +114 -0
  41. data/test/{tc_model_encode.rb → tc_model_think_blink.rb} +58 -13
  42. data/test/tc_types.rb +39 -0
  43. metadata +7 -6
@@ -18,13 +18,12 @@
18
18
  # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19
19
 
20
20
  module SlowBlink
21
+
21
22
  module Annotatable
22
23
 
23
24
  # @return [Array<Annotation>]
24
25
  attr_reader :annotes
25
26
 
26
- # @private
27
- #
28
27
  # @param annotes [Array<Annotation,Integer>]
29
28
  def annote(annotes)
30
29
  annotes.each do |a|
@@ -1,3 +1,4 @@
1
+
1
2
  # Copyright (c) 2016 Cameron Harper
2
3
  #
3
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy of
@@ -18,12 +19,18 @@
18
19
  # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19
20
 
20
21
  module SlowBlink
22
+
21
23
  class Annotation
22
24
 
25
+ # @macro location
23
26
  attr_reader :location
27
+
28
+ # @return [String]
24
29
  attr_reader :id
30
+
31
+ # @return [Integer]
25
32
  attr_reader :value
26
-
33
+
27
34
  # @param id [String] any string
28
35
  # @param value [String] any string
29
36
  # @param location [String]
@@ -19,6 +19,7 @@
19
19
 
20
20
  module SlowBlink
21
21
 
22
+ # @api private
22
23
  module CompactEncoder
23
24
 
24
25
  # @!method getU8(input)
@@ -1,3 +1,4 @@
1
+
1
2
  # Copyright (c) 2016 Cameron Harper
2
3
  #
3
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy of
@@ -18,6 +19,7 @@
18
19
  # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19
20
 
20
21
  module SlowBlink
22
+
21
23
  class Definition
22
24
 
23
25
  include Annotatable
@@ -26,14 +28,13 @@ module SlowBlink
26
28
  self == other
27
29
  end
28
30
 
29
- # @return [String]
31
+ # @macro location
30
32
  attr_reader :location
31
33
 
32
- # @return [String]
34
+ # @return [NameWithID]
33
35
  attr_reader :nameWithID
34
36
 
35
- # @return [ENUMERATION]
36
- # @return [Type]
37
+ # @return [Type,ENUMERATION]
37
38
  attr_reader :type
38
39
 
39
40
  # @param namespace [Namespace]
@@ -41,25 +42,48 @@ module SlowBlink
41
42
  @ns = namespace
42
43
  end
43
44
 
44
- # @private
45
- #
46
45
  # @param nameWithID [NameWithID]
47
46
  # @param type [ENUMERATION, Type]
48
47
  # @param location [String]
49
48
  def initialize(nameWithID, type, location)
50
49
  @annotes = {}
51
- @schema = nil
52
50
  @type = type
53
51
  @location = location
54
52
  @nameWithID = nameWithID
55
53
  @ns = nil
56
54
  end
57
55
 
56
+ # @api private
57
+ # Resolve references, enforce constraints, and detect cycles
58
+ #
59
+ # @param schema [Schema] schema this definition belongs to
60
+ # @param stack [nil, Array] objects that depend on this object
61
+ # @return [true,false] linked?
58
62
  def link(schema, stack=[])
59
- if @schema.nil?
60
- @schema = @type.link(schema, @ns, stack << self)
63
+
64
+ # a definition can resolve to a definition only if there is a dynamic
65
+ # link somewhere in the chain
66
+ sf = stack.each
67
+ begin
68
+ loop do
69
+ if sf.next == self
70
+ loop do
71
+ begin
72
+ f = sf.next
73
+ if f.respond_to? "dynamic?".to_sym and f.dynamic?
74
+ return schema
75
+ end
76
+ rescue StopIteration
77
+ raise Error.new "#{self.location}: error: invalid cycle detected"
78
+ end
79
+ end
80
+ end
81
+ end
82
+ rescue StopIteration
61
83
  end
62
- @schema
84
+
85
+ @type.link(schema, @ns, stack << self)
86
+
63
87
  end
64
88
 
65
89
  end
@@ -27,8 +27,6 @@ module SlowBlink
27
27
  self == other
28
28
  end
29
29
 
30
- # @private
31
- #
32
30
  # @param syms [Array<Sym>] symbol list
33
31
  def initialize(syms)
34
32
  @annotes = {}
@@ -37,20 +35,28 @@ module SlowBlink
37
35
  @schema = nil
38
36
  end
39
37
 
38
+ # @api private
39
+ #
40
+ # Resolve references, enforce constraints, and detect cycles
41
+ #
42
+ # @param schema [Schema] schema this definition belongs to
43
+ # @param ns [Namespace] namespace this definition belongs to
44
+ # @param stack [nil, Array] objects that depend on this object
45
+ # @return [true,false] linked?
40
46
  def link(schema, ns, stack=[])
41
47
  if @schema.nil?
42
48
  value = 0
43
- errors = 0
44
- @syms = {}
49
+ @syms = {}
50
+ @schema = schema
45
51
  @rawSyms.each do |s|
46
52
  if @syms[s.name]
47
- puts "#{s.location}: error: duplicate name '#{s.name}' (first defined at #{@syms[s.name].location})"
48
- errors += 1
53
+ Log.error "#{s.location}: error: symbols within an enumeration must have unique names ('#{s.name}' first appears at #{@syms[s.name].location})"
54
+ @schema = nil
49
55
  else
50
56
  if s.val
51
57
  if @syms.values.include? s.val
52
- puts "#{s.location}: error: duplicate value"
53
- errors += 1
58
+ Log.error "#{s.location}: error: values of symbols must be distinct ('#{s.val}' first appears at #{@syms[s.val].location})"
59
+ @schema = nil
54
60
  else
55
61
  value = s.val + 1
56
62
  end
@@ -60,10 +66,7 @@ module SlowBlink
60
66
  end
61
67
  @syms[s.name] = s
62
68
  end
63
- end
64
- if errors == 0
65
- @schema = schema
66
- end
69
+ end
67
70
  end
68
71
  @schema
69
72
  end
@@ -23,7 +23,7 @@ module SlowBlink
23
23
 
24
24
  include Annotatable
25
25
 
26
- # @return [String]
26
+ # @macro location
27
27
  attr_reader :location
28
28
 
29
29
  # @return [Type]
@@ -38,8 +38,6 @@ module SlowBlink
38
38
  @opt
39
39
  end
40
40
 
41
- # @private
42
- #
43
41
  # @param nameWithID [NameWithID]
44
42
  # @param type [Type]
45
43
  # @param opt [true,false] field is optional?
@@ -53,14 +51,17 @@ module SlowBlink
53
51
  @nameWithID = nameWithID
54
52
  end
55
53
 
56
- # @private
54
+ # @api private
55
+ #
56
+ # Resolve references, enforce constraints, and detect cycles
57
57
  #
58
- # @!macro common_link
58
+ # @param schema [Schema] schema this definition belongs to
59
+ # @param ns [Namespace] namespace this definition belongs to
60
+ # @param stack [nil, Array] objects that depend on this object
61
+ # @return [true,false] linked?
59
62
  def link(schema,ns, stack=[])
60
63
  if @schema.nil?
61
- if @type.link(schema, ns, stack << self)
62
- @schema = schema
63
- end
64
+ @schema = @type.link(schema, ns, stack << self)
64
65
  end
65
66
  @schema
66
67
  end
@@ -27,7 +27,7 @@ module SlowBlink
27
27
  self == other
28
28
  end
29
29
 
30
- # @return [String]
30
+ # @macro location
31
31
  attr_reader :location
32
32
 
33
33
  # @return [NameWithID]
@@ -43,8 +43,6 @@ module SlowBlink
43
43
  @ns = namespace
44
44
  end
45
45
 
46
- # @private
47
- #
48
46
  # @param nameWithID [NameWithID]
49
47
  # @param superGroup [REF, nil]
50
48
  # @param fields [Array<Field>]
@@ -59,42 +57,82 @@ module SlowBlink
59
57
  @nameWithID = nameWithID
60
58
  @ns = nil
61
59
  end
62
-
63
- # @private
60
+
61
+ # @api private
62
+ #
63
+ # Resolve references, enforce constraints, and detect cycles
64
64
  #
65
- # @macro common_link
65
+ # @param schema [Schema] schema this definition belongs to
66
+ # @param stack [nil, Array] objects that depend on this object
67
+ # @return [true,false] linked?
66
68
  def link(schema,stack=[])
69
+
67
70
  if @schema.nil?
68
- errors = 0
71
+
72
+ # a definition can resolve to a definition only if there is a dynamic
73
+ # link somewhere in the chain
74
+ sf = stack.each
75
+ begin
76
+ loop do
77
+ if sf.next == self
78
+ loop do
79
+ begin
80
+ f = sf.next
81
+ if f.respond_to? "dynamic?".to_sym and f.dynamic?
82
+ return schema
83
+ end
84
+ rescue StopIteration
85
+ raise Error.new "#{self.location}: error: invalid cycle detected"
86
+ end
87
+ end
88
+ end
89
+ end
90
+ rescue StopIteration
91
+ end
92
+
93
+ error = false
69
94
  @fields = {}
70
95
  if !@superGroup or (@superGroup and @superGroup.link(schema, @ns, stack << self))
71
96
  if !@superGroup or @superGroup.ref.is_a?(Group)
72
97
  if @superGroup
73
- @superGroup.ref.fields.each do |f|
74
- @fields[f.nameWithID.name] = f
75
- end
76
- end
77
- @rawFields.each do |f|
78
- if @fields[f.nameWithID.name]
79
- puts "#{f.location}: error: duplicate field name '#{f.nameWithID.name}' (first defined at #{@fields[f.nameWithID.name].location})"
80
- errors += 1
98
+ if @superGroup.dynamic_reference?
99
+ Log.error "#{@superGroup.location}: error: reference to supergroup must not be dynamic"
100
+ error = true
81
101
  else
82
- if f.link(schema, @ns, stack.dup << self)
102
+ @superGroup.ref.fields.each do |f|
83
103
  @fields[f.nameWithID.name] = f
84
- else
85
- errors += 1
86
104
  end
87
105
  end
88
106
  end
89
- if errors == 0
90
- @schema = schema
107
+ if !error
108
+ @rawFields.each do |f|
109
+ if @fields[f.nameWithID.name]
110
+ Log.error "#{f.location}: error: field names must be unique within a group ('#{f.nameWithID.name}' first appears at #{@fields[f.nameWithID.name].location})"
111
+ error = true
112
+ else
113
+ if f.link(schema, @ns, stack.dup << self)
114
+ @fields[f.nameWithID.name] = f
115
+ else
116
+ error = true
117
+ end
118
+ end
119
+ end
91
120
  end
92
121
  else
93
- puts "#{@superGroup.location}: error: superGroup '#{@superGroup.qname}' must resolve to a group definition"
122
+ Log.error "#{@superGroup.location}: error: reference to supergroup must resolve to group definition"
123
+ error = true
94
124
  end
125
+ else
126
+ error = true
127
+ end
128
+
129
+ if !error
130
+ @schema = schema
95
131
  end
132
+
96
133
  end
97
- @schema
134
+
135
+ @schema
98
136
  end
99
137
 
100
138
  # @param name [String] name of field
@@ -104,8 +142,7 @@ module SlowBlink
104
142
  @fields[name]
105
143
  end
106
144
 
107
- # Is this group a sub group of the super group?
108
- #
145
+ # @api private
109
146
  # @param superGroup [Group]
110
147
  # @return [true,false]
111
148
  def group_kind_of?(superGroup)
@@ -22,14 +22,17 @@ module SlowBlink
22
22
  # Blink Specification 7.3
23
23
  class IncrementalAnnotation
24
24
 
25
+ # @return [SchemaRef, DefinitionRef, DefinitionTypeRef, FieldRef, FieldTypeRef]
25
26
  attr_reader :componentReference
27
+
28
+ # @return [Array<Integer,Annotation>]
26
29
  attr_reader :annotes
30
+
31
+ # @macro location
27
32
  attr_reader :location
28
33
 
29
- # @private
30
- #
31
34
  # @param componentReference [SchemaRef, DefinitionRef, DefinitionTypeRef, FieldRef, FieldTypeRef] annotation target
32
- # @param annotations [Array<Integer,Annotation>]
35
+ # @param annotes [Array<Integer,Annotation>]
33
36
  # @param location [String]
34
37
  def initialize(componentReference, annotes, location)
35
38
  @componentReference = componentReference
@@ -38,7 +41,7 @@ module SlowBlink
38
41
  @schema = nil
39
42
  end
40
43
 
41
- # @private
44
+ # @api private
42
45
  #
43
46
  # Apply annotes to targets
44
47
  #
@@ -22,7 +22,7 @@ module SlowBlink
22
22
  class INTEGER < Type
23
23
  end
24
24
 
25
- # Blink Specification 3.1
25
+ # Blink Specification 3.1
26
26
  class I8 < INTEGER
27
27
  RANGE = Range.new(-128, 127)
28
28
  end
@@ -17,49 +17,32 @@
17
17
  # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
18
  # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19
19
 
20
- require "test/unit"
21
- require 'slow_blink'
20
+ module SlowBlink
22
21
 
23
- class TestModel < Test::Unit::TestCase
22
+ class Log
24
23
 
25
- include SlowBlink
26
-
27
- def test_think_blink
28
- rawSchema = <<-eos
29
- OrderExecuted/0x4c ->
30
- string Symbol,
31
- u64 OrderId,
32
- u32 Price,
33
- u32 Qty,
34
- u8 MatchId
35
- eos
36
- schema = Schema.new(SchemaBuffer.new(rawSchema))
37
- model = Message::Model.new(schema)
38
- end
39
-
40
- def test_from_compact
41
- rawSchema = <<-eos
42
- OrderExecuted/0x4c ->
43
- string Symbol,
44
- u64 OrderId,
45
- u32 Price,
46
- u32 Qty,
47
- u8 MatchId
48
- eos
49
- schema = Schema.new(SchemaBuffer.new(rawSchema))
24
+ @file = STDERR
25
+
26
+ def self.file=(file)
27
+ @file = file
28
+ end
29
+
30
+ def self.file
31
+ @file
32
+ end
33
+
34
+ def self.error(msg)
35
+ if @file
36
+ @file.puts(msg)
37
+ end
38
+ end
39
+
40
+ def self.info(msg)
41
+ if @file
42
+ @file.puts(msg)
43
+ end
44
+ end
50
45
 
51
- input = "\x0b\x4c\x05hello\x00\x01\x02\x03"
52
- model = Message::Model.new(schema)
53
-
54
- message = model.decode_compact(input)
55
-
56
- assert_equal("hello", message["Symbol"])
57
- assert_equal(0, message["OrderId"])
58
- assert_equal(1, message["Price"])
59
- assert_equal(2, message["Qty"])
60
- assert_equal(3, message["MatchId"])
61
46
  end
62
47
 
63
-
64
-
65
48
  end
@@ -19,68 +19,62 @@
19
19
 
20
20
  module SlowBlink::Message
21
21
 
22
- module BINARY
22
+ class BINARY
23
23
 
24
- module CLASS
25
-
26
- def opt?
27
- @opt
28
- end
24
+ def self.opt?
25
+ @opt
26
+ end
29
27
 
30
- def from_compact!(input)
31
- value = input.getBinary!
32
- if value
33
- if !@size or value.size <= @size
34
- self.new(value)
35
- else
36
- raise Error.new "W8: Binary value exceeds maximum size"
37
- end
38
- elsif @opt
39
- self.new(nil)
28
+ def self.from_compact!(input)
29
+ value = input.getBinary!
30
+ if value
31
+ if !@size or value.size <= @size
32
+ self.new(value)
40
33
  else
41
- raise Error.new "W5: Value cannot be null"
34
+ raise Error.new "W8: Binary value exceeds maximum size"
42
35
  end
36
+ elsif @opt
37
+ self.new(nil)
38
+ else
39
+ raise Error.new "W5: Value cannot be null"
43
40
  end
44
-
45
- def size
46
- @type.size
47
- end
48
-
49
41
  end
50
42
 
51
- module INSTANCE
43
+ def self.size
44
+ @type.size
45
+ end
52
46
 
53
- def set(value)
54
- if value
55
- if value.kind_of? String
56
- if !self.class.size or value.size <= self.class.size
57
- @value = value
58
- else
59
- raise Error.new "string cannot be larger than #{self.class.size} bytes"
60
- end
47
+ def set(value)
48
+ if value
49
+ if value.kind_of? String
50
+ if !self.class.size or value.size <= self.class.size
51
+ @value = value
61
52
  else
62
- raise Error.new "expecting a string type"
53
+ raise Error.new "string cannot be larger than #{self.class.size} bytes"
63
54
  end
64
- elsif self.class.opt?
65
- @value = nil
66
55
  else
67
- raise Error.new "string cannot be null"
56
+ raise Error.new "expecting a string type"
68
57
  end
58
+ elsif self.class.opt?
59
+ @value = nil
60
+ else
61
+ raise Error.new "string cannot be null"
69
62
  end
63
+ end
70
64
 
71
- def get
72
- @value
73
- end
74
-
75
- def initialize(value)
76
- set(value)
77
- end
65
+ def get
66
+ @value
67
+ end
78
68
 
79
- def to_compact(out)
80
- out.putBinary(@value)
81
- end
69
+ def initialize(value)
70
+ set(value)
71
+ end
82
72
 
73
+ def to_compact(out)
74
+ out.putBinary(@value)
83
75
  end
76
+
77
+
84
78
 
85
79
  end
86
80
 
@@ -19,50 +19,42 @@
19
19
 
20
20
  module SlowBlink::Message
21
21
 
22
- module BOOLEAN
23
-
24
- module CLASS
25
-
26
- def from_compact!(input)
27
- self.new(input.getBool!)
28
- end
22
+ class BOOLEAN
29
23
 
24
+ def self.from_compact!(input)
25
+ self.new(input.getBool!)
30
26
  end
31
27
 
32
- module INSTANCE
33
-
34
- def set(value)
35
- if value
36
- if value.kind_of? TrueClass or value.kind_of? FalseClass
37
- @value = value
38
- else
39
- raise "expecting true/false"
40
- end
41
- elsif self.class.opt?
42
- @value = nil
28
+ def set(value)
29
+ if value
30
+ if value.kind_of? TrueClass or value.kind_of? FalseClass
31
+ @value = value
43
32
  else
44
- raise Error.new "value unacceptable"
33
+ raise "expecting true/false"
45
34
  end
35
+ elsif self.class.opt?
36
+ @value = nil
37
+ else
38
+ raise Error.new "value unacceptable"
46
39
  end
40
+ end
47
41
 
48
- def get
49
- @value
50
- end
51
-
52
- def initialize(value)
53
- if value
54
- set(value)
55
- else
56
- @value = nil
57
- end
58
- end
42
+ def get
43
+ @value
44
+ end
59
45
 
60
- def to_compact(out)
61
- out.putBool(@value)
46
+ def initialize(value)
47
+ if value
48
+ set(value)
49
+ else
50
+ @value = nil
62
51
  end
63
-
64
52
  end
65
53
 
54
+ def to_compact(out)
55
+ out.putBool(@value)
56
+ end
57
+
66
58
  end
67
59
 
68
60
  end
@@ -19,14 +19,9 @@
19
19
 
20
20
  module SlowBlink::Message
21
21
 
22
- module DATE
22
+ class DATE
23
23
 
24
- module CLASS
25
- end
26
-
27
- module INSTANCE
28
- end
29
-
24
+
30
25
  end
31
26
 
32
27
  end