modl 0.3.15 → 0.3.16

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: 19862a8b989bb41687946af65e7368ee2c9ab88794498d9bc0383dba94bbd1ad
4
- data.tar.gz: e1b01ea144720b3b96f7ee412c843154fdb10acf6f84ebd72e24e23a5aef7f25
3
+ metadata.gz: de1a3cee98476becc60a2c7dab825c65c30b47e5e8b017ae30c23b8505937e41
4
+ data.tar.gz: 85150763932b4136124d120017881baaf34c528cc989709ecc139eaf563bc868
5
5
  SHA512:
6
- metadata.gz: eea7c86691b1e027737cbefbb92644731f96d049fbdf2bf894c0ea971679536f9111ff0c670ce2785b6346664df90e813bd5cce2c3f8b6360e1d91e2cbe94446
7
- data.tar.gz: e059d05d456ab4f73bc11b5dc62f50e7a291d00158063c4cc43ca7d3a3f5b9b1da09457bf3bf3f44d41d896576e3879efb49398434aa088b3229b64d50a12882
6
+ metadata.gz: 0276b480cfe85fa983b0deac3ca030f5a79d25e6676c781cf3ca8868162adfb30d837d29af4d26d935e41888819b57b9f83141d41d0311dd2fb8ab634e2799c5
7
+ data.tar.gz: d2e5547d0fd8225d3739d8d2c3754f40b7b77f0df6f5d415a42201f5dd696beb8f1d25e33c2ee18b635efc15bdc268df20ad97c7188c742825d498234312314f
@@ -1,3 +1,8 @@
1
+ 0.3.16
2
+ ===
3
+ - Use latest ruby runtime.
4
+ - Add support for `*array` keyword.
5
+
1
6
  0.3.15
2
7
  ===
3
8
  - Interpreter Error: undefined method `text' for nil:NilClass. GitHub issue #23
@@ -1667,7 +1667,7 @@
1667
1667
  },
1668
1668
  {
1669
1669
  "id": "176",
1670
- "input": "_var=2;\n*L=\"http://s3-eu-west-1.amazonaws.com/modltestfiles/testing.txt!\";\nprint=%update_date\n",
1670
+ "input": "_var=2;\n*L=\"http://modl.uk/tests/testing.txt!\";\nprint=%update_date\n",
1671
1671
  "expected_output": "{\n \"print\": \"20180921 08:20 2\"\n}",
1672
1672
  "tested_features": [
1673
1673
  "object_ref",
@@ -3011,5 +3011,14 @@
3011
3011
  "escape"
3012
3012
  ],
3013
3013
  "minimised_modl": "_letters=abc;key=\"\\%letters\""
3014
+ },
3015
+ {
3016
+ "id": "316",
3017
+ "input": "*array(\n *id=p;\n *name=people;\n *of=person\n );\n\n *class(\n *id=n;\n *name=name\n );\n\n *class(\n *id=a;\n *name=age\n );\n\n *class(\n *id=person;\n *assign=[\n [n;a]\n ]\n );\n\n data(\n p[[John;18];[Jane;20]];\n person=[Fred;21]\n );\n p[[Mary;18];[Mungo;19];[Midge;20]];\n person=[Rod;23]\n",
3018
+ "expected_output": "{\n \"data\": {\n \"people\": [\n {\n \"name\": \"John\",\n \"age\": 18\n },\n {\n \"name\": \"Jane\",\n \"age\": 20\n }\n ],\n \"person\": {\n \"name\": \"Fred\",\n \"age\": 21\n }\n },\n \"people\": [\n {\n \"name\": \"Mary\",\n \"age\": 18\n },\n {\n \"name\": \"Mungo\",\n \"age\": 19\n },\n {\n \"name\": \"Midge\",\n \"age\": 20\n }\n ],\n \"person\": {\n \"name\": \"Rod\",\n \"age\": 23\n }\n}",
3019
+ "tested_features": [
3020
+ "*arrays"
3021
+ ],
3022
+ "minimised_modl": "*array(*id=p;*name=people;*of=person);*class(*id=n;*name=name);*class(*id=a;*name=age);*class(*id=person;*assign=[[n;a]]);data(p[[John;18];[Jane;20]];person=[Fred;21]);p[[Mary;18];[Mungo;19];[Midge;20]];person=[Rod;23]"
3014
3023
  }
3015
3024
  ]
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The MIT License (MIT)
4
+ #
5
+ # Copyright (c) 2019 NUM Technology Ltd
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in
15
+ # all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ # THE SOFTWARE.
24
+
25
+ module MODL
26
+ module Parser
27
+ # This class handles the conversion of objects that refer to arrays into instances of those arrays.
28
+ # It works recursively since array usage can be nested.
29
+ class ArrayProcessor
30
+ # How deep can the class structure be?
31
+ MAX_RECURSION_DEPTH = 50
32
+ # global is a GlobalParseContext and obj is the extracted Array or Hash from MODL::Parser::Parsed.extract_json
33
+ def self.process(global, obj)
34
+ # Process each object in the array or just process the object if its a hash.
35
+ # Any other object is ignored.
36
+ raise StandardError, 'parameter "global" should be a GlobalParseContext' unless global.is_a?(GlobalParseContext)
37
+
38
+ if obj.is_a? Array
39
+ obj.each do |o|
40
+ process_obj global, o if o.is_a? Hash
41
+ end
42
+ elsif obj.is_a? Hash
43
+ process_obj global, obj
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ # Process the contents of the supplied array
50
+ def self.process_array(global, the_array, k, value)
51
+
52
+ return [k, value] if value.length.zero?
53
+ field_count = value[0].length
54
+ return [k, value] if field_count.zero?
55
+
56
+ # Get the class for the 'of' field of the array.
57
+ clazz = global.classs the_array.of
58
+ raise StandardError, 'No class with id or name =' + the_array.of + ' could be found.' if clazz.nil?
59
+
60
+ # Get the *assign array from the class and make sure we have an entry of size field_count
61
+ assignment_list = clazz.keylist_of_length field_count
62
+ raise StandardError, 'No assignment list of length ' + field_count.to_s + ' for class with id or name =' + the_array.of + ' could be found.' if assignment_list.nil?
63
+
64
+ result = []
65
+
66
+ value.each do |record|
67
+ object = {}
68
+ i = 0
69
+ assignment_list.each do |field|
70
+ field_class = global.classs field
71
+ if field_class
72
+ object[field_class.name_or_id] = record[i]
73
+ else
74
+ object[field] = record[i]
75
+ end
76
+ i += 1
77
+ end
78
+ result << object
79
+ end
80
+
81
+ return [the_array.name_or_id, result]
82
+ end
83
+
84
+ # Replace the existing object with the new array instance and a new key
85
+ # We need to keep the same key order, hence this method below
86
+ def self.replace_value(obj, old_k, new_k, new_v)
87
+ tmp = obj.dup
88
+ obj.clear
89
+ tmp.keys.each do |tmpk|
90
+ tmpv = tmp[tmpk]
91
+ if tmpk == old_k
92
+ obj[new_k] = new_v
93
+ else
94
+ obj[tmpk] = tmpv
95
+ end
96
+ end
97
+ end
98
+
99
+ def self.process_obj(global, obj)
100
+ obj.keys.each do |k|
101
+ value = obj[k]
102
+ # Does the key refer to an array that we have parsed or loaded?
103
+ the_array = global.arrays(k)
104
+ if the_array
105
+ # Yes so convert this value to an instance of that array
106
+ new_k, new_v = process_array global, the_array, k, value
107
+ # Replace the existing object with the new array instance and a new key
108
+ # We need to keep the same key order, hence this method below
109
+ replace_value obj, k, new_k, new_v
110
+ else
111
+ new_v = value
112
+ end
113
+ # Recurse into the value in case it has contents that also refer to arrays.
114
+ process global, new_v
115
+ end
116
+ end
117
+
118
+ end
119
+ end
120
+ end
@@ -57,7 +57,7 @@ module MODL
57
57
  new_k, new_v = process_class global, k, value
58
58
  # Replace the existing object with the new class instance and a new key
59
59
  # We need to keep the same key order, hence this method below
60
- replaceValue(obj, k, new_k, new_v)
60
+ replace_value(obj, k, new_k, new_v)
61
61
  else
62
62
  new_v = value
63
63
  end
@@ -66,7 +66,7 @@ module MODL
66
66
  end
67
67
  end
68
68
 
69
- def self.replaceValue(obj, old_k, new_k, new_v)
69
+ def self.replace_value(obj, old_k, new_k, new_v)
70
70
  tmp = obj.dup
71
71
  obj.clear
72
72
  tmp.keys.each do |tmpk|
@@ -252,7 +252,7 @@ module MODL
252
252
 
253
253
  # Replace the value for this key if we've changed anything.
254
254
  if new_value[new_k] != new_v
255
- replaceValue(new_value, new_k, new_k, new_v)
255
+ replace_value(new_value, new_k, new_k, new_v)
256
256
  end
257
257
  end
258
258
  elsif new_value.is_a?(Array)
@@ -49,7 +49,7 @@ module MODL
49
49
  force = file_name.end_with?('!')
50
50
  file_name = Sutil.head(file_name) if force
51
51
  file_name << '.modl' unless file_name.end_with?('.txt', '.modl')
52
- file_name, new_val = RefProcessor.deref file_name, global if file_name.include?('%')
52
+ file_name, _new_val = RefProcessor.deref file_name, global if file_name.include?('%')
53
53
  if force
54
54
  # Don't use the cache if we're forcing a reload.
55
55
  @cache.evict(file_name)
@@ -56,6 +56,9 @@ module MODL
56
56
  @syntax_version = 1
57
57
  @interpreter_syntax_version = 1
58
58
  @loaded_files = []
59
+ # Arrays
60
+ @arrays_by_id = {}
61
+ @arrays_by_name = {}
59
62
  end
60
63
 
61
64
  def loaded_file(str)
@@ -103,6 +106,17 @@ module MODL
103
106
  end
104
107
  end
105
108
 
109
+ def arrays(key)
110
+ if key.is_a? String
111
+ result = @arrays_by_id[key]
112
+ result = @arrays_by_name[key] if result.nil?
113
+ result
114
+ elsif key.is_a? MODLArray
115
+ @arrays_by_id[key.id] = key if key.id
116
+ @arrays_by_name[key.name] = key if key.name
117
+ end
118
+ end
119
+
106
120
  def merge_pairs(other)
107
121
  @pairs.merge!(other.all_pairs)
108
122
  end
@@ -125,6 +139,10 @@ module MODL
125
139
  @classes_by_id.keys.include?(key) || @classes_by_name.keys.include?(key)
126
140
  end
127
141
 
142
+ def has_array?(key)
143
+ @arrays_by_id.keys.include?(key) || @arrays_by_name.keys.include?(key)
144
+ end
145
+
128
146
  def has_user_method?(key)
129
147
  @methods_hash.keys.include?(key)
130
148
  end
@@ -27,6 +27,7 @@ require 'modl/parser/MODLParserVisitor'
27
27
  require 'modl/parser/MODLLexer'
28
28
  require 'modl/parser/MODLParser'
29
29
  require 'modl/parser/class_processor'
30
+ require 'modl/parser/array_processor'
30
31
  require 'modl/parser/orphan_handler'
31
32
  require 'modl/parser/parser'
32
33
  require 'json'
@@ -68,6 +69,7 @@ module MODL
68
69
 
69
70
  # Process any class definitions used by the MODL file.
70
71
  MODL::Parser::ClassProcessor.process(parsed.global, interpreted)
72
+ MODL::Parser::ArrayProcessor.process(parsed.global, interpreted)
71
73
  MODL::Parser::InstructionProcessor.process(parsed.global, interpreted)
72
74
  # If the result is a simple string then just return it.
73
75
  interpreted
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The MIT License (MIT)
4
+ #
5
+ # Copyright (c) 2019 NUM Technology Ltd
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in
15
+ # all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ # THE SOFTWARE.
24
+
25
+ module MODL
26
+ module Parser
27
+ # Represents a *array defined, or loaded by, a MODL document.
28
+ class MODLArray
29
+ attr_accessor :id
30
+ attr_accessor :name
31
+ attr_accessor :of
32
+
33
+ def initialize
34
+ @content = {}
35
+ end
36
+
37
+ def name_or_id
38
+ @name.nil? ? @id : @name
39
+ end
40
+ end
41
+
42
+ # Extract an array from a ParsedPair object
43
+ class ArrayExtractor
44
+ def self.extract(pair, global)
45
+ return unless pair.type == 'array'
46
+
47
+ the_array = MODLArray.new
48
+ map = pair.map if pair.map
49
+ map = pair.valueItem&.value&.map if pair.valueItem&.value&.map
50
+
51
+ map.mapItems.each do |item|
52
+ next unless item&.pair&.type
53
+
54
+ case item&.pair&.type
55
+ when 'id'
56
+ str_value = item.pair.valueItem.value.primitive.string.string
57
+ the_array.id = str_value
58
+ when 'name'
59
+ str_value = item.pair.valueItem.value.primitive.string.string
60
+ the_array.name = str_value
61
+ when 'of'
62
+ str_value = item.pair.valueItem.value.primitive.string.string
63
+ the_array.of = str_value
64
+ else
65
+ # Ignore
66
+ end
67
+ end
68
+
69
+ raise InterpreterError, 'Missing id for *array' if the_array.id.nil?
70
+
71
+ # Make sure the array name isn't redefining an existing array
72
+ if !global.has_array?(the_array.id) && !global.has_array?(the_array.name)
73
+
74
+ # store the arrays by id and name to make them easier to find later
75
+ global.arrays(the_array)
76
+ else
77
+ id = the_array.id.nil? ? 'undefined' : the_array.id
78
+ name = the_array.name.nil? ? 'undefined' : the_array.name
79
+ raise InterpreterError, '*Array name or id already defined - cannot redefine: ' + id + ', ' + name
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -30,6 +30,7 @@ require 'modl/parser/file_importer'
30
30
  require 'antlr4/runtime/parse_cancellation_exception'
31
31
  require 'modl/parser/sutil'
32
32
  require 'modl/parser/modl_class'
33
+ require 'modl/parser/modl_array'
33
34
  require 'modl/parser/modl_method'
34
35
  require 'modl/parser/modl_index'
35
36
  require 'modl/parser/modl_keylist'
@@ -211,6 +212,8 @@ module MODL
211
212
  @final = false
212
213
  @file_importer = FileImporter.instance
213
214
  @loaded = false
215
+ @array = nil
216
+ @map = nil
214
217
  end
215
218
 
216
219
  def find_property(key)
@@ -284,6 +287,7 @@ module MODL
284
287
  return if @type == 'import'
285
288
  return if @type == 'allow'
286
289
  return if @type == 'expect'
290
+ return if @type == 'array'
287
291
 
288
292
  {@key => @text}
289
293
  end
@@ -336,6 +340,8 @@ module MODL
336
340
  case @type
337
341
  when 'class'
338
342
  ClassExtractor.extract(self, @global)
343
+ when 'array'
344
+ ArrayExtractor.extract(self, @global)
339
345
  when 'id'
340
346
  extract_value
341
347
  when 'name'
@@ -478,6 +484,8 @@ module MODL
478
484
  @type = 'hidden' if @key.start_with? '_'
479
485
  @type = 'allow' if @key.downcase == '*allow'
480
486
  @type = 'expect' if @key.downcase == '*expect'
487
+ @type = 'of' if @key.downcase == '*of'
488
+ @type = 'array' if @key.downcase == '*array'
481
489
  end
482
490
  end
483
491
 
@@ -22,7 +22,6 @@
22
22
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
23
  # THE SOFTWARE.
24
24
 
25
- require 'modl/parser/parsed'
26
25
  require 'punycode'
27
26
  require 'modl/parser/sutil'
28
27
 
@@ -24,6 +24,6 @@
24
24
 
25
25
  module MODL
26
26
  module Parser
27
- VERSION = "0.3.15"
27
+ VERSION = "0.3.16"
28
28
  end
29
29
  end
@@ -25,6 +25,6 @@ Gem::Specification.new do |spec|
25
25
 
26
26
  spec.add_development_dependency 'rake', '~> 10.0'
27
27
  spec.add_development_dependency 'rspec', '~> 3.0'
28
- spec.add_runtime_dependency 'antlr4-runtime', '= 0.2.8'
28
+ spec.add_runtime_dependency 'antlr4-runtime', '= 0.2.9'
29
29
  spec.add_runtime_dependency 'punycode4r', '>= 0.2.0'
30
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: modl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.15
4
+ version: 0.3.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tony Walmsley
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-07-05 00:00:00.000000000 Z
11
+ date: 2019-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - '='
46
46
  - !ruby/object:Gem::Version
47
- version: 0.2.8
47
+ version: 0.2.9
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - '='
53
53
  - !ruby/object:Gem::Version
54
- version: 0.2.8
54
+ version: 0.2.9
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: punycode4r
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -113,12 +113,14 @@ files:
113
113
  - lib/modl/parser/MODLParserBaseVisitor.rb
114
114
  - lib/modl/parser/MODLParserListener.rb
115
115
  - lib/modl/parser/MODLParserVisitor.rb
116
+ - lib/modl/parser/array_processor.rb
116
117
  - lib/modl/parser/class_processor.rb
117
118
  - lib/modl/parser/evaluator.rb
118
119
  - lib/modl/parser/file_importer.rb
119
120
  - lib/modl/parser/global_parse_context.rb
120
121
  - lib/modl/parser/instruction_processor.rb
121
122
  - lib/modl/parser/interpreter.rb
123
+ - lib/modl/parser/modl_array.rb
122
124
  - lib/modl/parser/modl_class.rb
123
125
  - lib/modl/parser/modl_index.rb
124
126
  - lib/modl/parser/modl_keylist.rb