ruby-terraform 1.7.0.pre.7 → 1.7.0.pre.8

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: 40166cca660dc61e95b7b9983f757c4e3c148005226006167adebea38c5922bb
4
- data.tar.gz: 8140497c2e9c0a7acb5bce2967157a47b796bb2e0c716b70477cfac936a55fbd
3
+ metadata.gz: 29d107877da7868db24f108a46175dcc3f72b92baa17453cfd588784ecadbbe5
4
+ data.tar.gz: 4c3f6114288c1428313eb48c08a48d48ef1c824dbdcaf3c1f770c45a694687bd
5
5
  SHA512:
6
- metadata.gz: a6d0e5d37e4a84ed32d97e12af6af490cbfd9d08323cc811e58dcdd7595f6aed067c9f7348a2da1ce591e7c00556c305df3e4492a8644006be864b54f1d8f475
7
- data.tar.gz: ff0ba6c53a93af497e79ec00a75f25baa2667ed86009a475d976ecf15b949c8eded5fde7a4e69b5ae1b7f0c6126df979d945a6b7165cfe479498c2f584171668
6
+ metadata.gz: ef8aa4827093bdd287a3473ba0d61ce2812152812e3f60b8836b4aff306992ca77d5c619da0f591bf5f05c5f8b5a77181bb535e0f10a80adc924cbf8251264b9
7
+ data.tar.gz: 72f79d40b6d54ec9d5ad5998e953633b856778e1d3d565fddcac05ae8a7b0dd299de73a575624342c394f4e3bc39ac16bb2c492ae7717f3ced03bf9962dade25
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ruby-terraform (1.7.0.pre.7)
4
+ ruby-terraform (1.7.0.pre.8)
5
5
  immutable-struct (~> 2.4)
6
6
  lino (~> 3.0)
7
7
 
@@ -115,17 +115,17 @@ GEM
115
115
  diff-lcs (>= 1.2.0, < 2.0)
116
116
  rspec-support (~> 3.11.0)
117
117
  rspec-support (3.11.0)
118
- rubocop (1.31.2)
118
+ rubocop (1.32.0)
119
119
  json (~> 2.3)
120
120
  parallel (~> 1.10)
121
121
  parser (>= 3.1.0.0)
122
122
  rainbow (>= 2.2.2, < 4.0)
123
123
  regexp_parser (>= 1.8, < 3.0)
124
124
  rexml (>= 3.2.5, < 4.0)
125
- rubocop-ast (>= 1.18.0, < 2.0)
125
+ rubocop-ast (>= 1.19.1, < 2.0)
126
126
  ruby-progressbar (~> 1.7)
127
127
  unicode-display_width (>= 1.4.0, < 3.0)
128
- rubocop-ast (1.18.0)
128
+ rubocop-ast (1.19.1)
129
129
  parser (>= 3.1.1.0)
130
130
  rubocop-rake (0.6.0)
131
131
  rubocop (~> 1.0)
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative './values'
4
+ require_relative './path_set'
4
5
 
5
6
  module RubyTerraform
6
7
  module Models
@@ -8,6 +9,7 @@ module RubyTerraform
8
9
  module Objects
9
10
  class << self
10
11
  # rubocop:disable Style/RedundantAssignment
12
+ # rubocop:disable Metrics/MethodLength
11
13
  def box(object, unknown: nil, sensitive: nil)
12
14
  initial = boxed_empty_by_value(object)
13
15
  object = symbolise(object)
@@ -16,135 +18,112 @@ module RubyTerraform
16
18
 
17
19
  return Values.unknown(sensitive: sensitive) if unknown == true
18
20
 
21
+ unless object.is_a?(Hash) || object.is_a?(Array)
22
+ return Values.known(object, sensitive: sensitive)
23
+ end
24
+
19
25
  boxed_unknown =
20
26
  box_unknown(unknown, sensitive: sensitive, initial: initial)
27
+
21
28
  boxed_object =
22
29
  box_known(object, sensitive: sensitive, initial: boxed_unknown)
23
30
 
24
31
  boxed_object
25
32
  end
26
-
33
+ # rubocop:enable Metrics/MethodLength
27
34
  # rubocop:enable Style/RedundantAssignment
28
35
 
29
- def paths(object, current = [], accumulator = [])
30
- normalised = normalise(object)
31
- if normalised.is_a?(Enumerable)
32
- normalised.inject(accumulator) do |a, e|
33
- paths(e[0], current + [e[1]], a)
34
- end
35
- else
36
- accumulator + [current]
37
- end
36
+ def paths(object)
37
+ PathSet.extract_from(object)
38
38
  end
39
39
 
40
- def known_values(paths, object: {}, sensitive: {})
41
- paths.map do |path|
42
- resolved = try_dig(object, path)
43
- resolved_sensitive = try_dig(sensitive, path) == true
40
+ def known_values(path_set, object: {}, sensitive: {})
41
+ path_set.paths.map do |path|
42
+ resolved = path.read(object)
43
+ resolved_sensitive = path.read(sensitive) == true
44
44
 
45
45
  Values.known(resolved, sensitive: resolved_sensitive)
46
46
  end
47
47
  end
48
48
 
49
- def unknown_values(paths, unknown: {}, sensitive: {})
50
- paths.map do |path|
51
- resolved = try_dig(unknown, path)
52
- resolved_sensitive = try_dig(sensitive, path) == true
49
+ def unknown_values(path_set, unknown: {}, sensitive: {})
50
+ path_set.paths.map do |path|
51
+ resolved = path.read(unknown)
52
+ resolved_sensitive = path.read(sensitive) == true
53
53
 
54
54
  resolved ? Values.unknown(sensitive: resolved_sensitive) : nil
55
55
  end
56
56
  end
57
57
 
58
+ def object(path_set, values,
59
+ sensitive: {},
60
+ initial: Values.empty_map,
61
+ filler: Values.omitted)
62
+ gaps = path_set.gaps
63
+ extra_values = gaps.paths.collect { |p| [p, filler] }
64
+
65
+ path_values = path_set.paths.zip(values) + extra_values
66
+ path_values = sort_by_path(path_values)
67
+
68
+ update_all(initial, path_values, sensitive)
69
+ end
70
+
58
71
  private
59
72
 
60
- # rubocop:disable Metrics/MethodLength
61
73
  def box_unknown(unknown, sensitive: {}, initial: Values.empty_map)
62
- unknown_paths = paths(unknown)
63
- if root_path(unknown_paths)
64
- return Values.unknown(sensitive: sensitive)
65
- end
66
-
74
+ path_set = paths(unknown)
67
75
  unknown_values = unknown_values(
68
- unknown_paths, unknown: unknown, sensitive: sensitive
76
+ path_set, unknown: unknown, sensitive: sensitive
69
77
  )
70
-
71
78
  object(
72
- unknown_paths, unknown_values,
73
- sensitive: sensitive, initial: initial
79
+ path_set, unknown_values, sensitive: sensitive, initial: initial
74
80
  )
75
81
  end
76
- # rubocop:enable Metrics/MethodLength
77
82
 
78
- # rubocop:disable Metrics/MethodLength
79
83
  def box_known(object, sensitive: {}, initial: Values.empty_map)
80
- object_paths = paths(object)
81
- if root_path(object_paths)
82
- return Values.known(object, sensitive: sensitive)
83
- end
84
-
84
+ path_set = paths(object)
85
85
  object_values = known_values(
86
- object_paths, object: object, sensitive: sensitive
86
+ path_set, object: object, sensitive: sensitive
87
87
  )
88
-
89
88
  object(
90
- object_paths, object_values,
91
- sensitive: sensitive, initial: initial
89
+ path_set, object_values, sensitive: sensitive, initial: initial
92
90
  )
93
91
  end
94
- # rubocop:enable Metrics/MethodLength
95
92
 
96
- def object(paths, values, sensitive: {}, initial: Values.empty_map)
97
- paths
98
- .zip(values)
99
- .each_with_object(initial) do |path_value, object|
93
+ def update_all(object, path_values, sensitive = {})
94
+ path_values.each_with_object(object) do |path_value, obj|
100
95
  path, value = path_value
101
- update_in(object, path, value, sensitive: sensitive)
96
+ update_in(obj, path, value, sensitive: sensitive)
102
97
  end
103
98
  end
104
99
 
105
100
  def update_in(object, path, value, sensitive: {})
106
- path.inject([[], path.drop(1)]) do |context, step|
107
- seen, remaining = context
108
- pointer = [seen, step, remaining]
109
-
110
- update_object_for_step(object, pointer, value, sensitive: sensitive)
111
- update_context_for_step(pointer)
101
+ path.traverse(object) do |obj, step|
102
+ update_object_for_step(
103
+ obj, step, value, sensitive: sensitive
104
+ )
112
105
  end
113
- object
114
106
  end
115
107
 
116
108
  # rubocop:disable Metrics/MethodLength
117
- def update_object_for_step(object, pointer, value, sensitive: {})
118
- seen, step, remaining = pointer
109
+ def update_object_for_step(object, step, value, sensitive: {})
110
+ parent = step.seen.read(object, default: object)
111
+ upcoming = step.remaining.first
119
112
 
120
- parent = try_dig(object, seen, default: object)
121
- upcoming = remaining.first
122
-
123
- resolved_sensitive = try_dig(sensitive, seen + [step]) == true
113
+ found_sensitive = step.seen.append(step.element).read(sensitive)
114
+ resolved_sensitive = found_sensitive == true
124
115
  resolved =
125
- if remaining.empty?
116
+ if step.remaining.empty?
126
117
  value
127
118
  else
128
119
  boxed_empty_by_key(upcoming, sensitive: resolved_sensitive)
129
120
  end
130
121
 
131
- parent[step] ||= resolved
132
- end
133
- # rubocop:enable Metrics/MethodLength
134
-
135
- def update_context_for_step(pointer)
136
- seen, step, remaining = pointer
137
- [seen + [step], remaining.drop(1)]
138
- end
122
+ parent[step.element] ||= resolved
139
123
 
140
- def try_dig(object, path, default: nil)
141
- return default if path.empty?
142
-
143
- result = object.dig(*path)
144
- result.nil? ? default : result
145
- rescue NoMethodError, TypeError
146
- default
124
+ object
147
125
  end
126
+ # rubocop:enable Metrics/MethodLength
148
127
 
149
128
  def boxed_empty_by_key(key, sensitive: false)
150
129
  if key.is_a?(Numeric)
@@ -169,22 +148,12 @@ module RubyTerraform
169
148
  end
170
149
  end
171
150
 
172
- def normalise(object)
173
- case object
174
- when Array then object.each_with_index.to_a
175
- when Hash
176
- object.to_a.map do |e|
177
- [e[1], e[0].to_sym]
178
- end
179
- else object
180
- end
181
- end
182
-
183
151
  def symbolise(object)
184
152
  case object
185
153
  when Hash
186
154
  object.to_h { |key, value| [key.to_sym, symbolise(value)] }
187
- else object
155
+ else
156
+ object
188
157
  end
189
158
  end
190
159
 
@@ -192,8 +161,8 @@ module RubyTerraform
192
161
  object ? symbolise(object) : native_empty_by_value(target)
193
162
  end
194
163
 
195
- def root_path(paths)
196
- paths.count == 1 && paths[0].empty?
164
+ def sort_by_path(path_values)
165
+ path_values.sort { |a, b| a[0] <=> b[0] }
197
166
  end
198
167
  end
199
168
  end
@@ -0,0 +1,160 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../value_equality'
4
+
5
+ module RubyTerraform
6
+ module Models
7
+ # rubocop:disable Metrics/ClassLength
8
+ class Path
9
+ class << self
10
+ def empty
11
+ new([])
12
+ end
13
+ end
14
+
15
+ extend Forwardable
16
+
17
+ include Comparable
18
+ include ValueEquality
19
+
20
+ def_delegators(:@elements, :first, :last, :length, :empty?)
21
+
22
+ attr_reader(:elements)
23
+
24
+ def initialize(elements)
25
+ @elements = elements.compact
26
+ end
27
+
28
+ def references_any_lists?
29
+ elements.any? { |e| e.is_a?(Numeric) }
30
+ end
31
+
32
+ def references_any_maps?
33
+ elements.any? { |e| e.is_a?(Symbol) }
34
+ end
35
+
36
+ def same_parent_collection?(other)
37
+ return true if self == other
38
+
39
+ left, right = diff(other)
40
+ left.length == 1 && right.length == 1
41
+ end
42
+
43
+ def list_indices
44
+ elements.each_with_index.inject([]) do |acc, element_index|
45
+ element, index = element_index
46
+ element.is_a?(Numeric) ? acc + [[index, element]] : acc
47
+ end
48
+ end
49
+
50
+ def to_location(index)
51
+ return self.class.new([]) if index.negative?
52
+
53
+ self.class.new(elements[0..index])
54
+ end
55
+
56
+ def before_location(index)
57
+ return self.class.new([]) if index.negative?
58
+
59
+ self.class.new(elements[0...index])
60
+ end
61
+
62
+ def append(element)
63
+ self.class.new(elements + [element])
64
+ end
65
+
66
+ def drop(count = 1)
67
+ self.class.new(elements.drop(count))
68
+ end
69
+
70
+ def diff(other)
71
+ left, right = match_lengths(elements, other.elements)
72
+ pairwise = left.zip(right)
73
+ difference = pairwise.drop_while { |e| e[0] == e[1] }
74
+ difference = difference.empty? ? [[], []] : difference.transpose
75
+ difference.map { |e| self.class.new(e) }
76
+ end
77
+
78
+ def traverse(initial, &block)
79
+ initial_context = initial_traversal_context(initial)
80
+ final_context = elements.inject(initial_context) do |context, element|
81
+ state = block.call(context[:state], context[:step])
82
+ next_traversal_context(state, context[:step], element)
83
+ end
84
+
85
+ final_context[:state]
86
+ end
87
+
88
+ def read(object, default: nil)
89
+ return default if empty?
90
+
91
+ result = object.dig(*elements)
92
+ result.nil? ? default : result
93
+ rescue NoMethodError, TypeError
94
+ default
95
+ end
96
+
97
+ def <=>(other)
98
+ return 0 if self == other
99
+
100
+ left, right = diff(other)
101
+ return -1 if left.empty?
102
+ return 1 if right.empty?
103
+
104
+ compare_numbers_before_symbols(left.first, right.first)
105
+ end
106
+
107
+ def state
108
+ [elements]
109
+ end
110
+
111
+ private
112
+
113
+ class TraversalStep
114
+ attr_reader(:seen, :element, :remaining)
115
+
116
+ def initialize(seen, element, remaining)
117
+ @seen = seen
118
+ @element = element
119
+ @remaining = remaining
120
+ end
121
+ end
122
+
123
+ def initial_traversal_context(state)
124
+ {
125
+ state: state,
126
+ step: TraversalStep.new(self.class.empty, first, drop(1))
127
+ }
128
+ end
129
+
130
+ def next_traversal_context(state, position, step)
131
+ {
132
+ state: state,
133
+ step: TraversalStep.new(position.seen.append(step),
134
+ position.remaining.first,
135
+ position.remaining.drop(1))
136
+ }
137
+ end
138
+
139
+ def compare_numbers_before_symbols(left, right)
140
+ return -1 if left.is_a?(Numeric) && right.is_a?(Symbol)
141
+ return 1 if left.is_a?(Symbol) && right.is_a?(Numeric)
142
+
143
+ left <=> right
144
+ end
145
+
146
+ def match_lengths(left, right)
147
+ max_length = [left.count, right.count].max
148
+ [
149
+ pad_to_length(left, max_length),
150
+ pad_to_length(right, max_length)
151
+ ]
152
+ end
153
+
154
+ def pad_to_length(array, target_length)
155
+ array.clone.fill(nil, array.count, target_length - array.count)
156
+ end
157
+ end
158
+ # rubocop:enable Metrics/ClassLength
159
+ end
160
+ end
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../value_equality'
4
+
5
+ module RubyTerraform
6
+ module Models
7
+ class PathSet
8
+ class << self
9
+ def empty
10
+ new([])
11
+ end
12
+
13
+ def extract_from(object)
14
+ empty.add_paths_from(object)
15
+ end
16
+ end
17
+
18
+ extend Forwardable
19
+
20
+ include ValueEquality
21
+
22
+ def_delegators(:@paths, :empty?)
23
+
24
+ attr_reader(:paths)
25
+
26
+ def initialize(paths)
27
+ @paths = paths
28
+ end
29
+
30
+ def add_paths_from(object)
31
+ self.class.new(paths + extract_paths_from(object))
32
+ end
33
+
34
+ def gaps
35
+ initial_context = { last: Path.new([]), complete: [] }
36
+ result = paths.sort.inject(initial_context) do |acc, path|
37
+ current_path = path
38
+ last_path = acc[:last]
39
+ missing_paths = determine_missing_paths(last_path, current_path)
40
+ updated_paths = acc[:complete] + missing_paths
41
+
42
+ { last: current_path, complete: updated_paths }
43
+ end
44
+
45
+ self.class.new(result[:complete])
46
+ end
47
+
48
+ def state
49
+ [paths]
50
+ end
51
+
52
+ private
53
+
54
+ def extract_paths_from(
55
+ object,
56
+ current = Path.new([]),
57
+ accumulator = []
58
+ )
59
+ normalised = normalise(object)
60
+ if normalised.is_a?(Enumerable)
61
+ normalised.inject(accumulator) do |a, e|
62
+ extract_paths_from(e[0], current.append(e[1]), a)
63
+ end
64
+ else
65
+ accumulator + [current]
66
+ end
67
+ end
68
+
69
+ def normalise(object)
70
+ case object
71
+ when Array then object.each_with_index.to_a
72
+ when Hash
73
+ object.to_a.map do |e|
74
+ [e[1], e[0].to_sym]
75
+ end
76
+ else
77
+ object
78
+ end
79
+ end
80
+
81
+ # rubocop:disable Metrics/MethodLength
82
+ def determine_missing_paths(last_path, current_path)
83
+ last_indices = resolve_last_indices(last_path, current_path)
84
+ current_indices = current_path.list_indices
85
+
86
+ current_indices.inject([]) do |acc, current_index|
87
+ current_location, current_element = current_index
88
+ last_index =
89
+ last_indices.find { |index| index[0] == current_location }
90
+ last_element = last_index[1]
91
+
92
+ next(acc) unless current_element.positive?
93
+
94
+ start_element = last_element.nil? ? 0 : last_element + 1
95
+ next(acc) if start_element == current_element
96
+
97
+ acc + create_missing_paths(
98
+ start_element, current_element, current_path, current_location
99
+ )
100
+ end
101
+ end
102
+ # rubocop:enable Metrics/MethodLength
103
+
104
+ # rubocop:disable Metrics/MethodLength
105
+ def resolve_last_indices(last_path, current_path)
106
+ last_indices = last_path.list_indices
107
+ current_indices = current_path.list_indices
108
+
109
+ current_indices.collect do |current_entry|
110
+ location, current_element = current_entry
111
+ last_entry = last_indices.find { |index| index[0] == location }
112
+ last_element = last_entry&.slice(1)
113
+ reset_entry = [location, nil]
114
+
115
+ next(reset_entry) unless last_element
116
+ next(reset_entry) if current_element < last_element
117
+
118
+ current_sub_path = current_path.to_location(location)
119
+ last_sub_path = last_path.to_location(location)
120
+
121
+ unless current_sub_path.same_parent_collection?(last_sub_path)
122
+ next(reset_entry)
123
+ end
124
+
125
+ last_entry
126
+ end
127
+ end
128
+ # rubocop:enable Metrics/MethodLength
129
+
130
+ def create_missing_paths(from, to, path, location)
131
+ (from...to).collect do |element|
132
+ path.before_location(location).append(element)
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyTerraform
4
- VERSION = '1.7.0.pre.7'
4
+ VERSION = '1.7.0.pre.8'
5
5
  end
@@ -601,7 +601,7 @@ module RubyTerraform
601
601
  # actions.
602
602
  #
603
603
  # You can optionally save the plan to a file, which you can then pass to
604
- # the {#apply} command to perform exactly the actions described in the plan.
604
+ # the {#read} command to perform exactly the actions described in the plan.
605
605
  #
606
606
  # @param parameters The parameters used to invoke the command
607
607
  # @option parameters [String] :plan The path to a directory containing
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-terraform
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.0.pre.7
4
+ version: 1.7.0.pre.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - InfraBlocks Maintainers
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-07-21 00:00:00.000000000 Z
11
+ date: 2022-07-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: immutable-struct
@@ -324,6 +324,8 @@ files:
324
324
  - lib/ruby_terraform/models/map.rb
325
325
  - lib/ruby_terraform/models/objects.rb
326
326
  - lib/ruby_terraform/models/omitted_value.rb
327
+ - lib/ruby_terraform/models/path.rb
328
+ - lib/ruby_terraform/models/path_set.rb
327
329
  - lib/ruby_terraform/models/plan.rb
328
330
  - lib/ruby_terraform/models/resource_change.rb
329
331
  - lib/ruby_terraform/models/unknown_value.rb