lens_protocol 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e330ea84f57d295938c63b8f7be46106032d0d9438bb9d7480128558986c6083
4
- data.tar.gz: d83edf16f446f69f48f273226c21e5919af854d77afdf112009155e860fc5627
3
+ metadata.gz: 2e6b3a409c1b4b90d80b5dbcb8f7b2df59337dd44e9209f4ad76865862395c4b
4
+ data.tar.gz: da0a946184d65b6ee47fe064deee9d10f175283fb730d18024505c0f9ae52b7b
5
5
  SHA512:
6
- metadata.gz: d13370582cca70182bb834e1b853d6bf71dc4fdc73acae6977b9c6a60426ff073b862381e6152ef990a7a87467de39ad951f75c53cca33124b69ac398742721c
7
- data.tar.gz: 10f0596856b4b876b3179bcddeb6c44b653a95063e28a98094c7a54a3a77f129997c9a303f62893616e6b624eadfe1de4a5b24c996e384afd936bc5a623674eb
6
+ metadata.gz: bee9ec7e1cdc7bccebf6ea5ffeb43a374975b80dee29783ff5085d8b9656b27b071aeb29a0a37ccc9512c2058f6bb8b931975b1e5a20ad5ce0e0d77f5f7bac04
7
+ data.tar.gz: 8dfb0904eeeaa824ee9966349a5280d6883227fc2826c321f33575122a047fe13f4a083e1ff0a551690c513c966d417943a6fad2cde2accdb80c36f8c351c32e
@@ -55,24 +55,30 @@ Style/MutableConstant:
55
55
  Style/RescueModifier:
56
56
  Enabled: false
57
57
 
58
+ Layout/LineLength:
59
+ Max: 120
60
+
58
61
  Layout/SpaceInsideHashLiteralBraces:
59
62
  Enabled: false
60
63
 
61
64
  Layout/MultilineMethodCallIndentation:
62
65
  Enabled: false
63
66
 
64
- Layout/TrailingBlankLines:
67
+ Layout/TrailingEmptyLines:
65
68
  Enabled: false
66
69
 
67
- Layout/IndentArray:
70
+ Layout/FirstArrayElementIndentation:
68
71
  EnforcedStyle: consistent
69
72
 
70
- Layout/AlignParameters:
73
+ Layout/ParameterAlignment:
71
74
  EnforcedStyle: with_fixed_indentation
72
75
 
73
76
  Layout/SpaceInLambdaLiteral:
74
77
  Enabled: false
75
78
 
79
+ Layout/EmptyLineAfterGuardClause:
80
+ Enabled: false
81
+
76
82
  Metrics:
77
83
  Enabled: false
78
84
 
@@ -93,6 +99,3 @@ Lint/AmbiguousOperator:
93
99
 
94
100
  Lint/AmbiguousBlockAssociation:
95
101
  Enabled: false
96
-
97
- Naming/UncommunicativeMethodParamName:
98
- Enabled: false
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lens_protocol (0.1.3)
4
+ lens_protocol (0.2.0)
5
5
  activesupport (>= 4.0)
6
6
  nokogiri
7
7
 
@@ -14,6 +14,7 @@ GEM
14
14
  minitest (~> 5.1)
15
15
  tzinfo (~> 1.1)
16
16
  zeitwerk (~> 2.2)
17
+ ast (2.4.0)
17
18
  byebug (11.0.1)
18
19
  coderay (1.1.2)
19
20
  concurrent-ruby (1.1.5)
@@ -36,6 +37,7 @@ GEM
36
37
  rspec (>= 2.99.0, < 4.0)
37
38
  i18n (1.8.2)
38
39
  concurrent-ruby (~> 1.0)
40
+ jaro_winkler (1.5.4)
39
41
  listen (3.2.0)
40
42
  rb-fsevent (~> 0.10, >= 0.10.3)
41
43
  rb-inotify (~> 0.9, >= 0.9.10)
@@ -45,11 +47,14 @@ GEM
45
47
  minitest (5.14.0)
46
48
  mustermann (1.0.3)
47
49
  nenv (0.3.0)
48
- nokogiri (1.10.8)
50
+ nokogiri (1.10.9)
49
51
  mini_portile2 (~> 2.4.0)
50
52
  notiffany (0.1.3)
51
53
  nenv (~> 0.1)
52
54
  shellany (~> 0.0)
55
+ parallel (1.19.1)
56
+ parser (2.7.0.4)
57
+ ast (~> 2.4.0)
53
58
  pry (0.12.2)
54
59
  coderay (~> 1.1.0)
55
60
  method_source (~> 0.9.0)
@@ -59,10 +64,12 @@ GEM
59
64
  rack (2.0.8)
60
65
  rack-protection (2.0.7)
61
66
  rack
67
+ rainbow (3.0.0)
62
68
  rake (13.0.1)
63
69
  rb-fsevent (0.10.3)
64
70
  rb-inotify (0.10.0)
65
71
  ffi (~> 1.0)
72
+ rexml (3.2.4)
66
73
  rspec (3.9.0)
67
74
  rspec-core (~> 3.9.0)
68
75
  rspec-expectations (~> 3.9.0)
@@ -76,6 +83,15 @@ GEM
76
83
  diff-lcs (>= 1.2.0, < 2.0)
77
84
  rspec-support (~> 3.9.0)
78
85
  rspec-support (3.9.0)
86
+ rubocop (0.80.1)
87
+ jaro_winkler (~> 1.5.1)
88
+ parallel (~> 1.10)
89
+ parser (>= 2.7.0.1)
90
+ rainbow (>= 2.2.2, < 4.0)
91
+ rexml
92
+ ruby-progressbar (~> 1.7)
93
+ unicode-display_width (>= 1.4.0, < 1.7)
94
+ ruby-progressbar (1.10.1)
79
95
  shellany (0.0.1)
80
96
  sinatra (2.0.7)
81
97
  mustermann (~> 1.0)
@@ -87,6 +103,7 @@ GEM
87
103
  tilt (2.0.10)
88
104
  tzinfo (1.2.6)
89
105
  thread_safe (~> 0.1)
106
+ unicode-display_width (1.6.1)
90
107
  zeitwerk (2.2.2)
91
108
 
92
109
  PLATFORMS
@@ -100,6 +117,7 @@ DEPENDENCIES
100
117
  pry-byebug
101
118
  rake (~> 13.0)
102
119
  rspec (~> 3.0)
120
+ rubocop (~> 0.80.0)
103
121
  sinatra
104
122
 
105
123
  BUNDLED WITH
data/README.md CHANGED
@@ -19,7 +19,7 @@ gem 'lens_protocol'
19
19
  ```ruby
20
20
  require 'lens_protocol'
21
21
  message = LensProtocol::OMA.parse(File.read('examples/oma/R360_1.oma'))
22
- message.values_of('SPH') # => [1.25, -0.5]
22
+ message.value_of('SPH') # => [1.25, -0.5]
23
23
  ```
24
24
 
25
25
  ### Generating an OMA file
@@ -30,4 +30,5 @@ Gem::Specification.new do |spec|
30
30
  spec.add_development_dependency 'pry'
31
31
  spec.add_development_dependency 'pry-byebug'
32
32
  spec.add_development_dependency 'sinatra'
33
+ spec.add_development_dependency 'rubocop', '~> 0.80.0'
33
34
  end
@@ -5,14 +5,18 @@ require 'lens_protocol/version'
5
5
  require 'lens_protocol/errors'
6
6
  require 'lens_protocol/oma/record'
7
7
  require 'lens_protocol/oma/message'
8
- require 'lens_protocol/oma/type/base'
9
- require 'lens_protocol/oma/type/text'
10
- require 'lens_protocol/oma/type/integer'
11
- require 'lens_protocol/oma/type/numeric'
12
- require 'lens_protocol/oma/type/trcfmt'
13
- require 'lens_protocol/oma/type/r'
8
+ require 'lens_protocol/oma/types/type'
9
+ require 'lens_protocol/oma/types/single'
10
+ require 'lens_protocol/oma/types/array'
11
+ require 'lens_protocol/oma/types/matrix'
12
+ require 'lens_protocol/oma/types/chiral'
13
+ require 'lens_protocol/oma/types/ignored'
14
+ require 'lens_protocol/oma/types/trcfmt'
15
+ require 'lens_protocol/oma/types/values/tracing_dataset'
14
16
  require 'lens_protocol/oma/types'
17
+ require 'lens_protocol/oma/line'
15
18
  require 'lens_protocol/oma/parser'
16
19
  require 'lens_protocol/oma/formatter'
20
+ require 'lens_protocol/oma/builder'
17
21
  require 'lens_protocol/oma'
18
22
  require 'lens_protocol/svg'
@@ -7,4 +7,7 @@ module LensProtocol
7
7
  super "#{msg}\n Line: #{line}"
8
8
  end
9
9
  end
10
+
11
+ class ValidationError < Error
12
+ end
10
13
  end
@@ -8,7 +8,7 @@ module LensProtocol
8
8
  end
9
9
 
10
10
  def generate *args
11
- Message.from_hash *args
11
+ Builder.new.build *args
12
12
  end
13
13
 
14
14
  def format *args
@@ -0,0 +1,18 @@
1
+ module LensProtocol
2
+ module OMA
3
+ class Builder
4
+ def build hash, types: {}
5
+ types = TYPES.merge(types)
6
+
7
+ hash.reduce Message.new do |message, (label, value)|
8
+ wrapped_value = types[label].wrap(value, hash, label)
9
+ if wrapped_value == :ignored
10
+ message
11
+ else
12
+ message.add_record(label, wrapped_value)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -13,10 +13,18 @@ module LensProtocol
13
13
 
14
14
  def format_lines message, types: {}
15
15
  types = TYPES.merge(types)
16
- message.records.values.flat_map do |record|
17
- types[record.label].format(record, message)
16
+ message.records.flat_map do |label, record|
17
+ format_record label, record.value, types
18
18
  end
19
19
  end
20
+
21
+ private
22
+
23
+ def format_record label, value, types
24
+ lines = types[label].format(label, value)
25
+ lines = lines.is_a?(Array) ? lines : [lines]
26
+ lines.map &:to_s
27
+ end
20
28
  end
21
29
  end
22
30
  end
@@ -0,0 +1,16 @@
1
+ module LensProtocol
2
+ module OMA
3
+ Line = Struct.new(:label, :data, :raw, keyword_init: true) do
4
+ def self.parse raw_line
5
+ raise ParsingError.new('The label separator is missing', raw_line) unless raw_line.include?('=')
6
+
7
+ label, data = raw_line.split('=', -1)
8
+ Line.new label: label, data: data, raw: raw_line
9
+ end
10
+
11
+ def to_s
12
+ "#{label}=#{data}"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -4,15 +4,12 @@ module LensProtocol
4
4
  attr_reader :records
5
5
 
6
6
  # Builds a message from a hash of record labels to record value.
7
- def self.from_hash hash
8
- hash.reduce new do |message, (label, value)|
9
- message.add_record(label, value)
10
- end
7
+ def self.from_hash *args
8
+ OMA.generate *args
11
9
  end
12
10
 
13
- def initialize records: {}, context: {}
11
+ def initialize records: {}
14
12
  @records = records
15
- @context = context
16
13
  end
17
14
 
18
15
  def add_record label, value
@@ -20,29 +17,6 @@ module LensProtocol
20
17
  self
21
18
  end
22
19
 
23
- def add_record_or_insert_values label, values
24
- @records[label] ||= Record.new(label: label, value: [])
25
- @records[label].value << values
26
- self
27
- end
28
-
29
- def add_record_or_concat_values label, values
30
- @records[label] ||= Record.new(label: label, value: [])
31
- @records[label].value.concat values
32
- self
33
- end
34
-
35
- def add_record_side_values label, side, values
36
- @records[label] ||= Record.new(label: label, value: [[], []])
37
- @records[label].value[side].concat values
38
- self
39
- end
40
-
41
- def set_context key, value
42
- @context[key] = value
43
- self
44
- end
45
-
46
20
  def value_of label, default = nil
47
21
  if include? label
48
22
  @records[label].value
@@ -60,45 +34,18 @@ module LensProtocol
60
34
  @records.empty?
61
35
  end
62
36
 
63
- def context key
64
- @context[key]
65
- end
66
-
67
37
  def to_hash
68
38
  Hash[*@records.flat_map { |label, record| [label, record.value] }]
69
39
  end
70
40
 
71
- # Returns the "R" reconds decoded radiuses according to the tracing format.
72
- def radius_data
73
- return [] unless value_of('TRCFMT') && value_of('R')
74
- [0, 1].map do |side|
75
- case Type::Trcfmt.number(value_of('TRCFMT')[side])
76
- when 0 # side not present
77
- []
78
- when 1 # ASCII format
79
- value_of('R')[side]
80
- else # unknown format
81
- return []
82
- end
83
- end
84
- end
85
-
86
41
  # Converts the "R" record values to polar coordinates.
87
42
  def tracing_in_polar_coordinates
88
- radius_data.map { |radiuses| radiuses_to_polar radiuses }
89
- end
90
-
91
- def radiuses_to_polar radiuses
92
- radiuses.map.with_index { |r, i| [i * 2 * Math::PI / radiuses.size, r] }
43
+ value_of('TRCFMT', []).map { |tracing_dataset| tracing_dataset&.in_polar_coordinates || [] }
93
44
  end
94
45
 
95
46
  # Converts the "R" record values to rectangular coordinates.
96
47
  def tracing_in_rectangular_coordinates
97
- radius_data.map { |radiuses| radiuses_to_rectangular radiuses }
98
- end
99
-
100
- def radiuses_to_rectangular radiuses
101
- radiuses_to_polar(radiuses).map { |(a, r)| [r * Math.cos(a), r * Math.sin(a)].map { |v| v.round 2 } }
48
+ value_of('TRCFMT', []).map { |tracing_dataset| tracing_dataset&.in_rectangular_coordinates || [] }
102
49
  end
103
50
 
104
51
  # Returns an array of SVG strings, one for each side. If the tracing format is not recognized
@@ -3,22 +3,30 @@ module LensProtocol
3
3
  class Parser
4
4
  def parse oma_str, types: {}
5
5
  types = TYPES.merge(types)
6
- normalize_line_endings(oma_str)
7
- .split("\n")
8
- .reduce(Message.new) { |message, line| parse_line line, message, types }
6
+ lines = convert_to_structured_lines normalize_line_endings(oma_str).split("\n")
7
+ parse_lines lines, types, Message.new
9
8
  end
10
9
 
11
10
  private
12
11
 
13
- def parse_line line, message, types
14
- raise ParsingError.new('The label separator is missing', line) unless line.include?('=')
15
- label, = line.split('=')
16
- types[label].parse(line, message)
17
- end
18
-
19
12
  def normalize_line_endings str
20
13
  str.to_s.gsub /\r\n?/, "\n"
21
14
  end
15
+
16
+ def convert_to_structured_lines lines
17
+ lines.map { |line| Line.parse line }
18
+ end
19
+
20
+ def parse_lines lines, types, message
21
+ line, *next_lines = lines
22
+ if line
23
+ value, next_lines = types[line.label].parse(line, next_lines)
24
+ message.add_record(line.label, value) if value
25
+ parse_lines next_lines, types, message
26
+ else
27
+ message
28
+ end
29
+ end
22
30
  end
23
31
  end
24
32
  end
@@ -3,7 +3,6 @@ module LensProtocol
3
3
  class Record
4
4
  attr_reader :label
5
5
 
6
- # May hold a single value, an array of values (on multi-value and chiral records), or an array of array of values (in R records for example)
7
6
  attr_reader :value
8
7
 
9
8
  def initialize label:, value:
@@ -1,84 +1,86 @@
1
1
  module LensProtocol
2
2
  module OMA
3
- TYPES = Hash.new { Type::Text.new }.merge(
4
- 'ACOAT' => Type::Text.new(mode: :chiral),
5
- 'ADD' => Type::Numeric.new(mode: :chiral, decimals: 2),
6
- 'AX' => Type::Numeric.new(mode: :chiral, decimals: 2),
7
- 'BACK' => Type::Numeric.new(mode: :chiral, decimals: 2),
8
- 'BCTHK' => Type::Numeric.new(mode: :chiral, decimals: 2),
9
- 'BEVM' => Type::Integer.new(mode: :chiral),
10
- 'BEVP' => Type::Integer.new(mode: :chiral),
11
- 'BSIZ' => Type::Integer.new(mode: :chiral),
12
- 'BVD' => Type::Integer.new(mode: :chiral),
13
- 'CRIB' => Type::Numeric.new(mode: :chiral, decimals: 2),
14
- 'CTHICK' => Type::Numeric.new(mode: :chiral, decimals: 3),
15
- 'CYL' => Type::Numeric.new(mode: :chiral, decimals: 2),
16
- 'DBL' => Type::Numeric.new,
17
- 'DIA' => Type::Numeric.new(mode: :chiral, decimals: 2),
18
- 'DRILLE' => Type::Text.new(mode: :matrix_of_values),
19
- 'ETYP' => Type::Integer.new,
20
- 'FCOCIN' => Type::Numeric.new(mode: :chiral, decimals: 2),
21
- 'FCOCUP' => Type::Numeric.new(mode: :chiral, decimals: 2),
22
- 'FCSGIN' => Type::Numeric.new(mode: :chiral, decimals: 2),
23
- 'FCSGUP' => Type::Numeric.new(mode: :chiral, decimals: 2),
24
- 'FCRV' => Type::Numeric.new(mode: :chiral, decimals: 2),
25
- 'FED' => Type::Numeric.new(mode: :chiral, decimals: 2),
26
- 'FPINB' => Type::Numeric.new(mode: :chiral, decimals: 2),
27
- 'FRNT' => Type::Numeric.new(mode: :chiral, decimals: 3),
28
- 'FTYP' => Type::Integer.new,
29
- 'FWD' => Type::Numeric.new(mode: :chiral),
30
- 'GDEPTH' => Type::Numeric.new(mode: :chiral, decimals: 2),
31
- 'GWIDTH' => Type::Numeric.new(mode: :chiral, decimals: 2),
32
- 'GRADIENT' => Type::Integer.new(mode: :chiral),
33
- 'HBOX' => Type::Numeric.new(mode: :chiral, decimals: 2),
34
- 'IPD' => Type::Numeric.new(mode: :chiral, decimals: 2),
35
- 'LDADD' => Type::Numeric.new(mode: :chiral),
36
- 'LDDRAX' => Type::Numeric.new(mode: :chiral),
37
- 'LDDRCYL' => Type::Numeric.new(mode: :chiral),
38
- 'LDDRSPH' => Type::Numeric.new(mode: :chiral),
39
- 'LDNAM' => Type::Text.new(mode: :chiral),
40
- 'LDNRAX' => Type::Numeric.new(mode: :chiral),
41
- 'LDNRCYL' => Type::Numeric.new(mode: :chiral),
42
- 'LDNRSPH' => Type::Numeric.new(mode: :chiral),
43
- 'LDVEN' => Type::Text.new(mode: :chiral),
44
- 'LIND' => Type::Numeric.new(mode: :chiral, decimals: 3),
45
- 'LMATID' => Type::Integer.new(mode: :chiral),
46
- 'LMATTYPE' => Type::Text.new(mode: :chiral),
47
- 'LNAM' => Type::Text.new(mode: :chiral),
48
- 'LTYPE' => Type::Text.new(mode: :chiral),
49
- 'MAXFRT' => Type::Numeric.new(mode: :chiral),
50
- 'MBASE' => Type::Numeric.new(mode: :chiral, decimals: 2),
51
- 'MINFRT' => Type::Numeric.new(mode: :chiral),
52
- 'MINEDG' => Type::Numeric.new(mode: :chiral, decimals: 2),
53
- 'MPD' => Type::Integer.new(mode: :chiral),
54
- 'NPD' => Type::Numeric.new(mode: :chiral, decimals: 2),
55
- 'OCHT' => Type::Numeric.new(mode: :chiral, decimals: 2),
56
- 'OPC' => Type::Text.new(mode: :chiral),
57
- 'OPTFRNT' => Type::Numeric.new(mode: :chiral),
58
- 'PANTO' => Type::Integer.new(mode: :chiral),
59
- 'PINB' => Type::Numeric.new(mode: :chiral, decimals: 2),
60
- 'POLAR' => Type::Integer.new(mode: :chiral),
61
- 'PRVA' => Type::Numeric.new(mode: :chiral, decimals: 1),
62
- 'PRVM' => Type::Numeric.new(mode: :chiral, decimals: 2),
63
- 'R' => Type::R.new,
64
- 'SEGHT' => Type::Numeric.new(mode: :chiral, decimals: 2),
65
- 'SGOCIN' => Type::Numeric.new(mode: :chiral, decimals: 2),
66
- 'SGOCUP' => Type::Numeric.new(mode: :chiral, decimals: 2),
67
- 'SPH' => Type::Numeric.new(mode: :chiral, decimals: 2),
68
- 'STATUS' => Type::Integer.new,
69
- 'THKP' => Type::Numeric.new(mode: :chiral, decimals: 2),
70
- 'TINT' => Type::Text.new(mode: :chiral),
71
- 'TRCFMT' => Type::Trcfmt.new(mode: :chiral),
72
- 'VIEWP' => Type::Text.new(mode: :array_of_values),
73
- 'VBOX' => Type::Numeric.new(mode: :chiral, decimals: 2),
74
- 'XSTATUS' => Type::Text.new(mode: :matrix_of_values),
75
- 'ZTILT' => Type::Integer.new(mode: :chiral),
76
- '_BLANK' => Type::Text.new(mode: :matrix_of_values),
77
- '_LLVAL' => Type::Integer.new(mode: :chiral),
78
- '_PRVA1' => Type::Integer.new(mode: :chiral),
79
- '_PRVA2' => Type::Integer.new(mode: :chiral),
80
- '_PRVM1' => Type::Numeric.new(mode: :chiral, decimals: 1),
81
- '_PRVM2' => Type::Numeric.new(mode: :chiral, decimals: 1),
3
+ TYPES = Hash.new { Types::Single.new }.merge(
4
+ 'ACOAT' => Types::Chiral.new,
5
+ 'ADD' => Types::Chiral.new(value_type: :numeric, decimals: 2),
6
+ 'AX' => Types::Chiral.new(value_type: :numeric, decimals: 2),
7
+ 'BACK' => Types::Chiral.new(value_type: :numeric, decimals: 2),
8
+ 'BCTHK' => Types::Chiral.new(value_type: :numeric, decimals: 2),
9
+ 'BEVM' => Types::Chiral.new(value_type: :integer),
10
+ 'BEVP' => Types::Chiral.new(value_type: :integer),
11
+ 'BSIZ' => Types::Chiral.new(value_type: :integer),
12
+ 'BVD' => Types::Chiral.new(value_type: :integer),
13
+ 'CRIB' => Types::Chiral.new(value_type: :numeric, decimals: 2),
14
+ 'CTHICK' => Types::Chiral.new(value_type: :numeric, decimals: 3),
15
+ 'CYL' => Types::Chiral.new(value_type: :numeric, decimals: 2),
16
+ 'DBL' => Types::Single.new(value_type: :numeric),
17
+ 'DIA' => Types::Chiral.new(value_type: :numeric, decimals: 2),
18
+ 'DRILLE' => Types::Matrix.new,
19
+ 'ETYP' => Types::Single.new(value_type: :integer),
20
+ 'FCOCIN' => Types::Chiral.new(value_type: :numeric, decimals: 2),
21
+ 'FCOCUP' => Types::Chiral.new(value_type: :numeric, decimals: 2),
22
+ 'FCSGIN' => Types::Chiral.new(value_type: :numeric, decimals: 2),
23
+ 'FCSGUP' => Types::Chiral.new(value_type: :numeric, decimals: 2),
24
+ 'FCRV' => Types::Chiral.new(value_type: :numeric, decimals: 2),
25
+ 'FED' => Types::Chiral.new(value_type: :numeric, decimals: 2),
26
+ 'FPINB' => Types::Chiral.new(value_type: :numeric, decimals: 2),
27
+ 'FRNT' => Types::Chiral.new(value_type: :numeric, decimals: 3),
28
+ 'FTYP' => Types::Single.new(value_type: :integer),
29
+ 'FWD' => Types::Chiral.new(value_type: :numeric),
30
+ 'GDEPTH' => Types::Chiral.new(value_type: :numeric, decimals: 2),
31
+ 'GWIDTH' => Types::Chiral.new(value_type: :numeric, decimals: 2),
32
+ 'GRADIENT' => Types::Chiral.new(value_type: :integer),
33
+ 'HBOX' => Types::Chiral.new(value_type: :numeric, decimals: 2),
34
+ 'IPD' => Types::Chiral.new(value_type: :numeric, decimals: 2),
35
+ 'LDADD' => Types::Chiral.new(value_type: :numeric),
36
+ 'LDDRAX' => Types::Chiral.new(value_type: :numeric),
37
+ 'LDDRCYL' => Types::Chiral.new(value_type: :numeric),
38
+ 'LDDRSPH' => Types::Chiral.new(value_type: :numeric),
39
+ 'LDNAM' => Types::Chiral.new,
40
+ 'LDNRAX' => Types::Chiral.new(value_type: :numeric),
41
+ 'LDNRCYL' => Types::Chiral.new(value_type: :numeric),
42
+ 'LDNRSPH' => Types::Chiral.new(value_type: :numeric),
43
+ 'LDVEN' => Types::Chiral.new,
44
+ 'LIND' => Types::Chiral.new(value_type: :numeric, decimals: 3),
45
+ 'LMATID' => Types::Chiral.new(value_type: :integer),
46
+ 'LMATTYPE' => Types::Chiral.new,
47
+ 'LNAM' => Types::Chiral.new,
48
+ 'LTYPE' => Types::Chiral.new,
49
+ 'MAXFRT' => Types::Chiral.new(value_type: :numeric),
50
+ 'MBASE' => Types::Chiral.new(value_type: :numeric, decimals: 2),
51
+ 'MINFRT' => Types::Chiral.new(value_type: :numeric),
52
+ 'MINEDG' => Types::Chiral.new(value_type: :numeric, decimals: 2),
53
+ 'MPD' => Types::Chiral.new(value_type: :integer),
54
+ 'NPD' => Types::Chiral.new(value_type: :numeric, decimals: 2),
55
+ 'OCHT' => Types::Chiral.new(value_type: :numeric, decimals: 2),
56
+ 'OPC' => Types::Chiral.new,
57
+ 'OPTFRNT' => Types::Chiral.new(value_type: :numeric),
58
+ 'PANTO' => Types::Chiral.new(value_type: :integer),
59
+ 'PINB' => Types::Chiral.new(value_type: :numeric, decimals: 2),
60
+ 'POLAR' => Types::Chiral.new(value_type: :integer),
61
+ 'PRVA' => Types::Chiral.new(value_type: :numeric, decimals: 1),
62
+ 'PRVM' => Types::Chiral.new(value_type: :numeric, decimals: 2),
63
+ 'R' => Types::Ignored.new,
64
+ 'SEGHT' => Types::Chiral.new(value_type: :numeric, decimals: 2),
65
+ 'SGOCIN' => Types::Chiral.new(value_type: :numeric, decimals: 2),
66
+ 'SGOCUP' => Types::Chiral.new(value_type: :numeric, decimals: 2),
67
+ 'SPH' => Types::Chiral.new(value_type: :numeric, decimals: 2),
68
+ 'STATUS' => Types::Single.new(value_type: :integer),
69
+ 'THKP' => Types::Chiral.new(value_type: :numeric, decimals: 2),
70
+ 'TINT' => Types::Chiral.new,
71
+ 'TRCFMT' => Types::Trcfmt.new,
72
+ 'VIEWP' => Types::Array.new,
73
+ 'VBOX' => Types::Chiral.new(value_type: :numeric, decimals: 2),
74
+ 'XSTATUS' => Types::Matrix.new,
75
+ 'ZTILT' => Types::Chiral.new(value_type: :integer),
76
+ '_BLANK' => Types::Matrix.new,
77
+ '_LLVAL' => Types::Chiral.new(value_type: :integer),
78
+ '_PRVA1' => Types::Chiral.new(value_type: :integer),
79
+ '_PRVA2' => Types::Chiral.new(value_type: :integer),
80
+ '_PRVM1' => Types::Chiral.new(value_type: :numeric, decimals: 1),
81
+ '_PRVM2' => Types::Chiral.new(value_type: :numeric, decimals: 1),
82
+ '_ETYP2' => Types::Chiral.new(value_type: :integer),
83
+ '_CTO' => Types::Chiral.new(value_type: :integer)
82
84
  )
83
85
  end
84
86
  end
@@ -0,0 +1,21 @@
1
+ module LensProtocol
2
+ module OMA
3
+ module Types
4
+ class Array < Type
5
+ def parse line, next_lines
6
+ values = parse_values line.data
7
+ [values, next_lines]
8
+ end
9
+
10
+ def wrap value, _message_hash, label
11
+ raise ValidationError, "#{label}: Expected an array of values. Got #{value}" unless value.is_a?(::Array)
12
+ value
13
+ end
14
+
15
+ def format label, values
16
+ build_line label, format_values(values)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,31 @@
1
+ module LensProtocol
2
+ module OMA
3
+ module Types
4
+ class Chiral < Type
5
+ def parse line, next_lines
6
+ values = make_chiral parse_values line.data
7
+ [values, next_lines]
8
+ end
9
+
10
+ def wrap value, _message_hash, _label
11
+ make_chiral Array(value)
12
+ end
13
+
14
+ def format label, values
15
+ data = values.select(&:present?).empty? ? '' : format_values(values)
16
+ build_line label, data
17
+ end
18
+
19
+ private
20
+
21
+ def make_chiral values
22
+ if values.size <= 1
23
+ [values[0], values[0]]
24
+ else
25
+ values[0..1]
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,15 @@
1
+ module LensProtocol
2
+ module OMA
3
+ module Types
4
+ class Ignored < Type
5
+ def parse _line, next_lines
6
+ [nil, next_lines]
7
+ end
8
+
9
+ def wrap _value, _message, _label
10
+ :ignored
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ module LensProtocol
2
+ module OMA
3
+ module Types
4
+ class Matrix < Type
5
+ def parse line, next_lines
6
+ same_label_lines, next_lines = next_lines.partition { |other_line| other_line.label == line.label }
7
+ values = [line, *same_label_lines].map { |line| parse_values line.data }
8
+ [values, next_lines]
9
+ end
10
+
11
+ def format label, values
12
+ values.map { |v| build_line label, format_values(v) }
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ module LensProtocol
2
+ module OMA
3
+ module Types
4
+ class Single < Type
5
+ def parse line, next_lines
6
+ value = parse_value line.data
7
+ [value, next_lines]
8
+ end
9
+
10
+ def wrap value, _message_hash, label
11
+ raise ValidationError, "#{label}: Expected a single value. Got #{value}" if value.respond_to?(:each)
12
+ value
13
+ end
14
+
15
+ def format label, value
16
+ build_line label, format_value(value)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,77 @@
1
+ module LensProtocol
2
+ module OMA
3
+ module Types
4
+ class Trcfmt < Type
5
+ def parse line, next_lines
6
+ dataset1, next_lines = extract_tracing_dataset [line, *next_lines]
7
+ dataset2, next_lines = extract_tracing_dataset next_lines
8
+
9
+ datasets = [dataset1, dataset2].compact
10
+ value = [
11
+ datasets.detect { |ds| ds.side == 'R' },
12
+ datasets.detect { |ds| ds.side == 'L' }
13
+ ]
14
+
15
+ [value, next_lines]
16
+ end
17
+
18
+ def wrap value, message_hash, _label
19
+ right_side, left_side = value
20
+ [
21
+ build_tracing_dataset(right_side, message_hash),
22
+ build_tracing_dataset(left_side, message_hash)
23
+ ]
24
+ end
25
+
26
+ def format label, chiral_value
27
+ chiral_value.compact.flat_map do |value|
28
+ [
29
+ build_line(label, format_values(value.trcfmt_values)),
30
+ *value.radius_data.each_slice(10).map { |vs| build_line('R', format_values(vs)) }
31
+ ]
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def extract_tracing_dataset lines
38
+ line, *next_lines = lines.drop_while { |line| line.label != 'TRCFMT' }
39
+
40
+ if line
41
+ trcfmt_values = parse_values line.data
42
+
43
+ radius_data = next_lines
44
+ .take_while { |line| line.label == 'R' }
45
+ .flat_map { |line| parse_radius_data line.data, trcfmt_values[0] }
46
+
47
+ dataset = Values::TracingDataset.new(trcfmt_values: trcfmt_values, radius_data: radius_data)
48
+ [dataset, next_lines.drop_while { |line| line.label == 'R' }]
49
+ else
50
+ [nil, []]
51
+ end
52
+ end
53
+
54
+ def parse_radius_data data, format
55
+ if format == '1'
56
+ parse_values data, :integer
57
+ else
58
+ data
59
+ end
60
+ end
61
+
62
+ def build_tracing_dataset value, message_hash
63
+ return unless value
64
+
65
+ _, _, _, side, = value
66
+ raise ValidationError, "Invalid TRCFMT value '#{value}'" unless %w[L R].include?(side)
67
+
68
+ r_values = message_hash['R']
69
+ raise ValidationError, "Invalid R value '#{r_values}'" unless r_values && r_values.size == 2
70
+
71
+ radius_data = r_values[side == 'R' ? 0 : 1]
72
+ Values::TracingDataset.new(trcfmt_values: value, radius_data: radius_data)
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,74 @@
1
+ module LensProtocol
2
+ module OMA
3
+ module Types
4
+ class Type
5
+ def initialize value_type: :string, decimals: nil
6
+ @value_type = value_type
7
+ @decimals = decimals
8
+ end
9
+
10
+ # Receives the current line and the lines after that.
11
+ # Must return the parsed value to store on the message, and the array of (possibly filtered) next lines.
12
+ def parse _line, _next_lines
13
+ raise NotImplementedError, self
14
+ end
15
+
16
+ # Used when building a message from a hash. Validations may be placed in the subclasses.
17
+ # TODO The message hash is only used for records like TRCFMT that need to access the R values, but having
18
+ # the R at the same level in the hash would not allow for building messages with TRCFMT and STHKFMT.
19
+ def wrap value, _message_hash, _label
20
+ value
21
+ end
22
+
23
+ # Receives a record label and value.
24
+ # Must return one line or and array of them.
25
+ def format _label, _value
26
+ raise NotImplementedError, self
27
+ end
28
+
29
+ private
30
+
31
+ def parse_value value, type = @value_type
32
+ case type
33
+ when :string
34
+ value if value != '?'
35
+ when :integer
36
+ Integer(value) rescue Float(value).round rescue nil
37
+ when :numeric
38
+ Float(value) rescue nil
39
+ else
40
+ raise "Value type '#{type}' not supported"
41
+ end
42
+ end
43
+
44
+ def parse_values data, type = @value_type
45
+ data.split(';', -1).map { |value| parse_value value, type }
46
+ end
47
+
48
+ def format_value value, type = @value_type
49
+ return nil unless value
50
+
51
+ case type
52
+ when :string
53
+ value
54
+ when :integer
55
+ value.round
56
+ when :numeric
57
+ @decimals ? "%.#{@decimals}f" % value : value
58
+ else
59
+ raise "Value type '#{type}' not supported"
60
+ end
61
+ end
62
+
63
+ def format_values values, type = @value_type
64
+ values = values.is_a?(::Array) ? values : [values]
65
+ values.map { |v| format_value v, type }.join(';')
66
+ end
67
+
68
+ def build_line label, data
69
+ Line.new label: label, data: data
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,42 @@
1
+ module LensProtocol
2
+ module OMA
3
+ module Types
4
+ module Values
5
+ class TracingDataset
6
+ attr_reader :trcfmt_values, :radius_data
7
+
8
+ def initialize trcfmt_values:, radius_data: []
9
+ @trcfmt_values = trcfmt_values
10
+ @radius_data = radius_data
11
+ end
12
+
13
+ def side
14
+ trcfmt_values[3]
15
+ end
16
+
17
+ def format
18
+ trcfmt_values[0]
19
+ end
20
+
21
+ def side_pos
22
+ side == 'R' ? 0 : 1
23
+ end
24
+
25
+ # Converts the radius data record values to polar coordinates.
26
+ def in_polar_coordinates
27
+ return [] unless recognized_format?
28
+ radius_data.map.with_index { |r, i| [i * 2 * Math::PI / radius_data.size, r] }
29
+ end
30
+
31
+ def in_rectangular_coordinates
32
+ in_polar_coordinates.map { |(a, r)| [r * Math.cos(a), r * Math.sin(a)].map { |v| v.round 2 } }
33
+ end
34
+
35
+ def recognized_format?
36
+ format == '1'
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,3 +1,3 @@
1
1
  module LensProtocol
2
- VERSION = '0.1.3'
2
+ VERSION = '0.2.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lens_protocol
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emmanuel Nicolau
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-04 00:00:00.000000000 Z
11
+ date: 2020-03-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -136,6 +136,20 @@ dependencies:
136
136
  - - ">="
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rubocop
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 0.80.0
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: 0.80.0
139
153
  description: A Ruby parser and builder for the OMA protocol (a.k.a. Data Communication
140
154
  Standard) that was developed by the Lens Processing & Technology Division of The
141
155
  Vision Council for interconnection of optical laboratory equipment.
@@ -175,17 +189,21 @@ files:
175
189
  - lib/lens_protocol.rb
176
190
  - lib/lens_protocol/errors.rb
177
191
  - lib/lens_protocol/oma.rb
192
+ - lib/lens_protocol/oma/builder.rb
178
193
  - lib/lens_protocol/oma/formatter.rb
194
+ - lib/lens_protocol/oma/line.rb
179
195
  - lib/lens_protocol/oma/message.rb
180
196
  - lib/lens_protocol/oma/parser.rb
181
197
  - lib/lens_protocol/oma/record.rb
182
- - lib/lens_protocol/oma/type/base.rb
183
- - lib/lens_protocol/oma/type/integer.rb
184
- - lib/lens_protocol/oma/type/numeric.rb
185
- - lib/lens_protocol/oma/type/r.rb
186
- - lib/lens_protocol/oma/type/text.rb
187
- - lib/lens_protocol/oma/type/trcfmt.rb
188
198
  - lib/lens_protocol/oma/types.rb
199
+ - lib/lens_protocol/oma/types/array.rb
200
+ - lib/lens_protocol/oma/types/chiral.rb
201
+ - lib/lens_protocol/oma/types/ignored.rb
202
+ - lib/lens_protocol/oma/types/matrix.rb
203
+ - lib/lens_protocol/oma/types/single.rb
204
+ - lib/lens_protocol/oma/types/trcfmt.rb
205
+ - lib/lens_protocol/oma/types/type.rb
206
+ - lib/lens_protocol/oma/types/values/tracing_dataset.rb
189
207
  - lib/lens_protocol/svg.rb
190
208
  - lib/lens_protocol/version.rb
191
209
  homepage: https://github.com/eeng/lens_protocol
@@ -206,7 +224,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
206
224
  - !ruby/object:Gem::Version
207
225
  version: '0'
208
226
  requirements: []
209
- rubygems_version: 3.1.2
227
+ rubygems_version: 3.0.0
210
228
  signing_key:
211
229
  specification_version: 4
212
230
  summary: LensProtocol is a Ruby parser and builder for the OMA protocol.
@@ -1,97 +0,0 @@
1
- module LensProtocol
2
- module OMA
3
- module Type
4
- class Base
5
- def initialize mode: :single_value
6
- @mode = mode
7
- end
8
-
9
- # Given a line and a message produces a new message with the record(s) corresponding to that line added to the message
10
- # @return [Message]
11
- def parse line, message
12
- label, data = label_and_data line
13
- case @mode
14
- when :single_value
15
- message.add_record label, parse_value(data)
16
- when :array_of_values
17
- message.add_record_or_concat_values label, parse_values(data)
18
- when :chiral
19
- message.add_record label, parse_chiral(data)
20
- when :matrix_of_values
21
- message.add_record_or_insert_values label, parse_values(data)
22
- else
23
- raise ArgumentError, "Mode #{@mode} not supported"
24
- end
25
- end
26
-
27
- # @return [Array of lines or a single one]
28
- def format record, _message
29
- case @mode
30
- when :single_value
31
- format_line record.label, [format_value(record.value)]
32
- when :array_of_values
33
- format_line record.label, format_values(record.value)
34
- when :chiral
35
- format_line record.label, format_chiral(record.value)
36
- when :matrix_of_values
37
- record.value.map do |value|
38
- format_line record.label, format_values(value)
39
- end
40
- else
41
- raise ArgumentError, "Mode #{@mode} not supported"
42
- end
43
- end
44
-
45
- private
46
-
47
- def label_and_data line
48
- label, data = line.split('=', -1)
49
- [label, data]
50
- end
51
-
52
- def label_and_values line
53
- label, data = label_and_data line
54
- [label, parse_values(data)]
55
- end
56
-
57
- def parse_values data
58
- data.split(';', -1).map { |value| parse_value value }
59
- end
60
-
61
- def parse_value value
62
- value if value != '?'
63
- end
64
-
65
- def parse_chiral values
66
- make_chiral parse_values values
67
- end
68
-
69
- def make_chiral values
70
- if values.size <= 1
71
- [values[0], values[0]]
72
- else
73
- values[0..1]
74
- end
75
- end
76
-
77
- def format_line label, values
78
- "#{label}=#{values.join(';')}"
79
- end
80
-
81
- def format_value value
82
- value
83
- end
84
-
85
- def format_values values
86
- values = values.is_a?(Array) ? values : [values]
87
- values.map { |v| format_value(v) }
88
- end
89
-
90
- def format_chiral value
91
- return [] if Array(value).select(&:present?).empty?
92
- make_chiral format_values value
93
- end
94
- end
95
- end
96
- end
97
- end
@@ -1,15 +0,0 @@
1
- module LensProtocol
2
- module OMA
3
- module Type
4
- class Integer < Base
5
- def parse_value value
6
- Integer(value) rescue Float(value).round rescue nil
7
- end
8
-
9
- def format_value value
10
- value.round if value
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,24 +0,0 @@
1
- module LensProtocol
2
- module OMA
3
- module Type
4
- class Numeric < Base
5
- def initialize decimals: nil, **opts
6
- super **opts
7
- @decimals = decimals
8
- end
9
-
10
- def parse_value value
11
- Float(value) rescue nil
12
- end
13
-
14
- def format_value value
15
- if value && @decimals
16
- "%.#{@decimals}f" % value
17
- else
18
- value
19
- end
20
- end
21
- end
22
- end
23
- end
24
- end
@@ -1,18 +0,0 @@
1
- module LensProtocol
2
- module OMA
3
- module Type
4
- class R < Base
5
- def parse line, message
6
- label, values = label_and_values line
7
- trcfmt = message.context(:last_trcfmt) or return message
8
- values = Trcfmt.number(trcfmt) == 1 ? values.map(&:to_i) : values
9
- message.add_record_side_values(label, Trcfmt.side_pos(trcfmt), values)
10
- end
11
-
12
- def format _record, _message
13
- [] # Formatted in Type::Trcfmt
14
- end
15
- end
16
- end
17
- end
18
- end
@@ -1,8 +0,0 @@
1
- module LensProtocol
2
- module OMA
3
- module Type
4
- class Text < Base
5
- end
6
- end
7
- end
8
- end
@@ -1,34 +0,0 @@
1
- module LensProtocol
2
- module OMA
3
- module Type
4
- class Trcfmt < Base
5
- def parse line, message
6
- label, values = label_and_values line
7
- side_pos = Trcfmt.side_pos values
8
- message.add_record_side_values(label, side_pos, values).set_context(:last_trcfmt, values)
9
- end
10
-
11
- def format record, message
12
- Array(record.value).select { |v| v&.any? }.flat_map do |values|
13
- trcfmt_line = format_line(record.label, values)
14
-
15
- side_pos = Trcfmt.side_pos values
16
- r_lines = message.value_of('R', [[], []])[side_pos].each_slice(10).map do |group|
17
- format_line('R', group)
18
- end
19
-
20
- [trcfmt_line, *r_lines]
21
- end
22
- end
23
-
24
- def self.side_pos values
25
- values[3] == 'R' ? 0 : 1
26
- end
27
-
28
- def self.number values
29
- values[0].to_i
30
- end
31
- end
32
- end
33
- end
34
- end