lens_protocol 0.1.3 → 0.2.0

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.
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