cfa 0.4.1 → 0.4.2
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 +4 -4
- data/lib/cfa/augeas_parser.rb +130 -65
- data/lib/cfa/base_model.rb +45 -9
- data/lib/cfa/matcher.rb +40 -4
- data/lib/cfa/placer.rb +40 -15
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a5ddfd0e34f669de02849ae3fcbc4ca3dafb664
|
4
|
+
data.tar.gz: b4d6d350b7a072b7168a9250454115c206630e53
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 265417fcbac259f04e42331f29918ebf4e575bc5e8f58d564af944355d12fc4dfd271bae09acb8213fa9cf6b5782189090d1e5f672d39d4b3687d025de9d43d1
|
7
|
+
data.tar.gz: 6862d7929f54bdf1673dd6f3721481fe7953a7a960b00ddc905254bd5dec4d608eec94ac36f388c959228e13fbe4876267eda2b5df3f661da7fb546262aca120
|
data/lib/cfa/augeas_parser.rb
CHANGED
@@ -3,6 +3,25 @@ require "forwardable"
|
|
3
3
|
require "cfa/placer"
|
4
4
|
|
5
5
|
module CFA
|
6
|
+
# A building block for {AugeasTree}.
|
7
|
+
#
|
8
|
+
# Intuitively the tree is made of hashes where keys may be duplicated,
|
9
|
+
# so it is implemented as a sequence of hashes with two keys, :key and :value.
|
10
|
+
#
|
11
|
+
# A `:key` is a String.
|
12
|
+
# The key may have a collection suffix "[]". Note that in contrast
|
13
|
+
# with the underlying {::Augeas} library, an integer index is not present
|
14
|
+
# (which should make it easier to modify collections of elements).
|
15
|
+
#
|
16
|
+
# A `:value` is either a String, or an {AugeasTree},
|
17
|
+
# or an {AugeasTreeValue} (which combines both).
|
18
|
+
#
|
19
|
+
# @return [Hash{Symbol => String, AugeasTree}]
|
20
|
+
#
|
21
|
+
# @todo Unify naming: entry, element
|
22
|
+
class AugeasElement < Hash
|
23
|
+
end
|
24
|
+
|
6
25
|
# Represents list of same config options in augeas.
|
7
26
|
# For example comments are often stored in collections.
|
8
27
|
class AugeasCollection
|
@@ -19,6 +38,7 @@ module CFA
|
|
19
38
|
element = placer.new_element(@tree)
|
20
39
|
element[:key] = augeas_name
|
21
40
|
element[:value] = value
|
41
|
+
# FIXME: load_collection missing here
|
22
42
|
end
|
23
43
|
|
24
44
|
def delete(value)
|
@@ -47,12 +67,12 @@ module CFA
|
|
47
67
|
end
|
48
68
|
end
|
49
69
|
|
50
|
-
# Represents node that
|
51
|
-
# For easier
|
70
|
+
# Represents a node that contains both a value and a subtree below it.
|
71
|
+
# For easier traversal it forwards `#[]` to the subtree.
|
52
72
|
class AugeasTreeValue
|
53
|
-
# value in node
|
73
|
+
# @return [String] the value in the node
|
54
74
|
attr_accessor :value
|
55
|
-
# subtree below node
|
75
|
+
# @return [AugeasTree] the subtree below the node
|
56
76
|
attr_accessor :tree
|
57
77
|
|
58
78
|
def initialize(tree, value)
|
@@ -60,32 +80,58 @@ module CFA
|
|
60
80
|
@value = value
|
61
81
|
end
|
62
82
|
|
63
|
-
|
64
|
-
|
83
|
+
# (see AugeasTree#[])
|
84
|
+
def [](key)
|
85
|
+
tree[key]
|
86
|
+
end
|
87
|
+
|
88
|
+
def ==(other)
|
89
|
+
[:class, :value, :tree].all? do |a|
|
90
|
+
public_send(a) == other.public_send(a)
|
91
|
+
end
|
65
92
|
end
|
93
|
+
|
94
|
+
# For objects of class Object, eql? is synonymous with ==:
|
95
|
+
# http://ruby-doc.org/core-2.3.3/Object.html#method-i-eql-3F
|
96
|
+
alias_method :eql?, :==
|
66
97
|
end
|
67
98
|
|
68
|
-
#
|
99
|
+
# Represents a parsed Augeas config tree with user friendly methods
|
69
100
|
class AugeasTree
|
70
|
-
#
|
101
|
+
# Low level access to Augeas structure
|
102
|
+
#
|
103
|
+
# An ordered mapping, represented by an Array of Hashes
|
104
|
+
# with the keys :key and :value.
|
105
|
+
#
|
106
|
+
# @see AugeasElement
|
107
|
+
#
|
108
|
+
# @return [Array<Hash{Symbol => String, AugeasTree}>]
|
71
109
|
attr_reader :data
|
72
110
|
|
73
111
|
def initialize
|
74
112
|
@data = []
|
75
113
|
end
|
76
114
|
|
115
|
+
# @return [AugeasCollection] collection for *key*
|
77
116
|
def collection(key)
|
78
117
|
AugeasCollection.new(self, key)
|
79
118
|
end
|
80
119
|
|
81
|
-
|
82
|
-
|
120
|
+
# @param [String, Matcher]
|
121
|
+
def delete(matcher)
|
122
|
+
unless matcher.is_a?(CFA::Matcher)
|
123
|
+
matcher = CFA::Matcher.new(key: matcher)
|
124
|
+
end
|
125
|
+
@data.reject!(&matcher)
|
83
126
|
end
|
84
127
|
|
85
|
-
#
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
128
|
+
# Adds the given *value* for *key* in the tree.
|
129
|
+
#
|
130
|
+
# By default an AppendPlacer is used which produces duplicate keys
|
131
|
+
# but ReplacePlacer can be used to replace the *first* duplicate.
|
132
|
+
# @param key [String]
|
133
|
+
# @param value [String,AugeasTree,AugeasTreeValue]
|
134
|
+
# @param placer [Placer] determines where to insert value in tree.
|
89
135
|
# Useful e.g. to specify order of keys or placing comment above of given
|
90
136
|
# key.
|
91
137
|
def add(key, value, placer = AppendPlacer.new)
|
@@ -94,10 +140,10 @@ module CFA
|
|
94
140
|
element[:value] = value
|
95
141
|
end
|
96
142
|
|
97
|
-
#
|
98
|
-
# @
|
99
|
-
#
|
100
|
-
#
|
143
|
+
# Finds given *key* in tree.
|
144
|
+
# @param key [String]
|
145
|
+
# @return [String,AugeasTree,AugeasTreeValue,nil] the first value for *key*,
|
146
|
+
# or `nil` if not found
|
101
147
|
def [](key)
|
102
148
|
entry = @data.find { |d| d[:key] == key }
|
103
149
|
return entry[:value] if entry
|
@@ -105,8 +151,10 @@ module CFA
|
|
105
151
|
nil
|
106
152
|
end
|
107
153
|
|
108
|
-
#
|
109
|
-
#
|
154
|
+
# Replace the first value for *key* with *value*.
|
155
|
+
# Append a new element if *key* did not exist.
|
156
|
+
# @param key [String]
|
157
|
+
# @param value [String, AugeasTree, AugeasTreeValue]
|
110
158
|
def []=(key, value)
|
111
159
|
entry = @data.find { |d| d[:key] == key }
|
112
160
|
if entry
|
@@ -119,12 +167,20 @@ module CFA
|
|
119
167
|
end
|
120
168
|
end
|
121
169
|
|
170
|
+
# @param matcher [Matcher]
|
171
|
+
# @return [Array<AugeasElement>] matching elements
|
122
172
|
def select(matcher)
|
123
173
|
@data.select(&matcher)
|
124
174
|
end
|
125
175
|
|
126
176
|
# @note for internal usage only
|
127
|
-
# @private
|
177
|
+
# @api private
|
178
|
+
#
|
179
|
+
# Initializes {#data} from *prefix* in *aug*.
|
180
|
+
# @param aug [::Augeas]
|
181
|
+
# @param prefix [String] Augeas path prefix
|
182
|
+
# @param keys_cache [AugeasKeysCache]
|
183
|
+
# @return [void]
|
128
184
|
def load_from_augeas(aug, prefix, keys_cache)
|
129
185
|
@data = keys_cache.keys_for_prefix(prefix).map do |key|
|
130
186
|
aug_key = prefix + "/" + key
|
@@ -136,7 +192,12 @@ module CFA
|
|
136
192
|
end
|
137
193
|
|
138
194
|
# @note for internal usage only
|
139
|
-
# @private
|
195
|
+
# @api private
|
196
|
+
#
|
197
|
+
# Saves {#data} to *prefix* in *aug*.
|
198
|
+
# @param aug [::Augeas]
|
199
|
+
# @param prefix [String] Augeas path prefix
|
200
|
+
# @return [void]
|
140
201
|
def save_to_augeas(aug, prefix)
|
141
202
|
arrays = {}
|
142
203
|
|
@@ -145,6 +206,14 @@ module CFA
|
|
145
206
|
end
|
146
207
|
end
|
147
208
|
|
209
|
+
def ==(other)
|
210
|
+
[:class, :data].all? { |a| public_send(a) == other.public_send(a) }
|
211
|
+
end
|
212
|
+
|
213
|
+
# For objects of class Object, eql? is synonymous with ==:
|
214
|
+
# http://ruby-doc.org/core-2.3.3/Object.html#method-i-eql-3F
|
215
|
+
alias_method :eql?, :==
|
216
|
+
|
148
217
|
private
|
149
218
|
|
150
219
|
def save_entry(key, value, arrays, aug, prefix)
|
@@ -199,20 +268,22 @@ module CFA
|
|
199
268
|
end
|
200
269
|
|
201
270
|
# @example read, print, modify and serialize again
|
202
|
-
# require "
|
271
|
+
# require "cfa/augeas_parser"
|
203
272
|
#
|
204
|
-
# parser = CFA::AugeasParser.new("
|
273
|
+
# parser = CFA::AugeasParser.new("Sysconfig.lns")
|
205
274
|
# data = parser.parse(File.read("/etc/default/grub"))
|
206
275
|
#
|
207
276
|
# puts data["GRUB_DISABLE_OS_PROBER"]
|
208
277
|
# data["GRUB_DISABLE_OS_PROBER"] = "true"
|
209
278
|
# puts parser.serialize(data)
|
210
279
|
class AugeasParser
|
280
|
+
# @param lens [String] a lens name, like "Sysconfig.lns"
|
211
281
|
def initialize(lens)
|
212
282
|
@lens = lens
|
213
283
|
end
|
214
284
|
|
215
|
-
#
|
285
|
+
# @param raw_string [String] a string to be parsed
|
286
|
+
# @return [AugeasTree] the parsed data
|
216
287
|
def parse(raw_string)
|
217
288
|
@old_content = raw_string
|
218
289
|
|
@@ -232,7 +303,8 @@ module CFA
|
|
232
303
|
end
|
233
304
|
end
|
234
305
|
|
235
|
-
#
|
306
|
+
# @param data [AugeasTree] the data to be serialized
|
307
|
+
# @return [String] a string to be written
|
236
308
|
def serialize(data)
|
237
309
|
# open augeas without any autoloading and it should not touch disk and
|
238
310
|
# load lenses as needed only
|
@@ -248,13 +320,15 @@ module CFA
|
|
248
320
|
end
|
249
321
|
end
|
250
322
|
|
251
|
-
#
|
323
|
+
# @return [AugeasTree] an empty tree that can be filled
|
324
|
+
# for future serialization
|
252
325
|
def empty
|
253
326
|
AugeasTree.new
|
254
327
|
end
|
255
328
|
|
256
329
|
private
|
257
330
|
|
331
|
+
# @param aug [::Augeas]
|
258
332
|
def report_error(aug)
|
259
333
|
error = aug.error
|
260
334
|
# zero is no error, so problem in lense
|
@@ -267,53 +341,44 @@ module CFA
|
|
267
341
|
raise "Augeas parsing/serializing error: #{msg} at #{location}"
|
268
342
|
end
|
269
343
|
end
|
270
|
-
end
|
271
344
|
|
272
|
-
# Cache that holds all avaiable keys in augeas tree. It is used to
|
273
|
-
# prevent too many aug.match calls which are expensive.
|
274
|
-
class AugeasKeysCache
|
275
|
-
|
276
|
-
STORE_LEN = STORE_PREFIX.size
|
277
|
-
STORE_LEN_1 = STORE_LEN + 1
|
345
|
+
# Cache that holds all avaiable keys in augeas tree. It is used to
|
346
|
+
# prevent too many aug.match calls which are expensive.
|
347
|
+
class AugeasKeysCache
|
348
|
+
STORE_PREFIX = "/store".freeze
|
278
349
|
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
# returns list of keys available on given prefix
|
285
|
-
def keys_for_prefix(prefix)
|
286
|
-
cut = prefix.length > STORE_LEN ? STORE_LEN_1 : STORE_LEN
|
287
|
-
path = prefix[cut..-1]
|
288
|
-
path = path.split("/")
|
289
|
-
matches = path.reduce(@cache) { |a, e| a[e] }
|
350
|
+
# initialize cache from passed augeas object
|
351
|
+
def initialize(aug)
|
352
|
+
fill_cache(aug)
|
353
|
+
end
|
290
354
|
|
291
|
-
|
292
|
-
|
355
|
+
# returns list of keys available on given prefix
|
356
|
+
def keys_for_prefix(prefix)
|
357
|
+
@cache[prefix] || []
|
358
|
+
end
|
293
359
|
|
294
|
-
private
|
360
|
+
private
|
295
361
|
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
362
|
+
def fill_cache(aug)
|
363
|
+
@cache = {}
|
364
|
+
search_path = "#{STORE_PREFIX}/*"
|
365
|
+
loop do
|
366
|
+
matches = aug.match(search_path)
|
367
|
+
break if matches.empty?
|
368
|
+
assign_matches(matches, @cache)
|
303
369
|
|
304
|
-
|
370
|
+
search_path += "/*"
|
371
|
+
end
|
305
372
|
end
|
306
|
-
end
|
307
373
|
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
374
|
+
def assign_matches(matches, cache)
|
375
|
+
matches.each do |match|
|
376
|
+
split_index = match.rindex("/")
|
377
|
+
prefix = match[0..(split_index - 1)]
|
378
|
+
key = match[(split_index + 1)..-1]
|
379
|
+
cache[prefix] ||= []
|
380
|
+
cache[prefix] << key
|
314
381
|
end
|
315
|
-
|
316
|
-
target[leap] = {}
|
317
382
|
end
|
318
383
|
end
|
319
384
|
end
|
data/lib/cfa/base_model.rb
CHANGED
@@ -22,11 +22,28 @@ module CFA
|
|
22
22
|
self.data = parser.empty
|
23
23
|
end
|
24
24
|
|
25
|
+
# Serializes *data* using *parser*
|
26
|
+
# and writes the resulting String using *file_handler*.
|
27
|
+
# @return [void]
|
28
|
+
# @raise a *file_handler* specific error if *file_path* cannot be written
|
29
|
+
# e.g. due to missing permissions or living on a read only device.
|
30
|
+
# @raise a *parser* specific error. If *data* contain invalid values
|
31
|
+
# then *parser* may raise an error.
|
32
|
+
# A properly written BaseModel subclass should prevent that by preventing
|
33
|
+
# insertion of such values in the first place.
|
25
34
|
def save(changes_only: false)
|
26
35
|
merge_changes if changes_only
|
27
36
|
@file_handler.write(@file_path, @parser.serialize(data))
|
28
37
|
end
|
29
38
|
|
39
|
+
# Reads a String using *file_handler*
|
40
|
+
# and parses it with *parser*, storing the result in *data*.
|
41
|
+
# @return [void]
|
42
|
+
# @raise a *file_handler* specific error. If *file_path* does not exist
|
43
|
+
# or permission is not sufficient it may raise an error
|
44
|
+
# depending on the used file handler.
|
45
|
+
# @raise a *parser* specific error. If the parsed String is malformed, then
|
46
|
+
# depending on the used parser it may raise an error.
|
30
47
|
def load
|
31
48
|
self.data = @parser.parse(@file_handler.read(@file_path))
|
32
49
|
@loaded = true
|
@@ -65,21 +82,31 @@ module CFA
|
|
65
82
|
@default_file_handler = value
|
66
83
|
end
|
67
84
|
|
68
|
-
|
69
|
-
|
70
|
-
#
|
85
|
+
# Generates accessors for trivial key-value attributes
|
86
|
+
# @param attrs [Hash{Symbol => String}] mapping of methods to file keys
|
87
|
+
#
|
88
|
+
# @example Usage
|
89
|
+
# class FooModel < CFA::BaseModel
|
90
|
+
# attributes(
|
91
|
+
# server: "server",
|
92
|
+
# read_timeout: "ReadTimeout",
|
93
|
+
# write_timeout: "WriteTimeout"
|
94
|
+
# )
|
95
|
+
# ...
|
96
|
+
# end
|
71
97
|
def self.attributes(attrs)
|
72
|
-
attrs.each_pair do |
|
73
|
-
define_method(
|
74
|
-
generic_get(
|
98
|
+
attrs.each_pair do |method_name, key|
|
99
|
+
define_method(method_name) do
|
100
|
+
generic_get(key)
|
75
101
|
end
|
76
102
|
|
77
|
-
define_method(:"#{
|
78
|
-
generic_set(
|
103
|
+
define_method(:"#{method_name.to_s}=") do |value|
|
104
|
+
generic_set(key, value)
|
79
105
|
end
|
80
106
|
end
|
81
107
|
end
|
82
|
-
|
108
|
+
|
109
|
+
protected
|
83
110
|
|
84
111
|
attr_accessor :data
|
85
112
|
|
@@ -90,6 +117,9 @@ module CFA
|
|
90
117
|
data.merge(new_data)
|
91
118
|
end
|
92
119
|
|
120
|
+
# Modify an **existing** entry and return `true`,
|
121
|
+
# or do nothing and return `false`.
|
122
|
+
# @return [Boolean]
|
93
123
|
def modify(key, value)
|
94
124
|
# if already set, just change value
|
95
125
|
return false unless data[key]
|
@@ -98,14 +128,20 @@ module CFA
|
|
98
128
|
true
|
99
129
|
end
|
100
130
|
|
131
|
+
# Replace a commented out entry and return `true`,
|
132
|
+
# or do nothing and return `false`.
|
133
|
+
# @return [Boolean]
|
101
134
|
def uncomment(key, value)
|
102
135
|
# Try to find if it is commented out, so we can replace line
|
103
136
|
matcher = Matcher.new(
|
104
137
|
collection: "#comment",
|
138
|
+
# FIXME: this assumes a specific "=" syntax, bypassing the lens
|
139
|
+
# FIXME: this will match also "# If you set FOO=bar then..."
|
105
140
|
value_matcher: /(\s|^)#{key}\s*=/
|
106
141
|
)
|
107
142
|
return false unless data.data.any?(&matcher)
|
108
143
|
|
144
|
+
# FIXME: this assumes that *data* is an AugeasTree
|
109
145
|
data.add(key, value, ReplacePlacer.new(matcher))
|
110
146
|
true
|
111
147
|
end
|
data/lib/cfa/matcher.rb
CHANGED
@@ -1,9 +1,42 @@
|
|
1
1
|
module CFA
|
2
|
-
#
|
3
|
-
#
|
4
|
-
#
|
2
|
+
# The Matcher is used as a predicate on {AugeasElement}.
|
3
|
+
#
|
4
|
+
# Being a predicate, it is passed to methods such as Enumerable#select
|
5
|
+
# or Array#index, returning a Boolean meaning whether a match was found.
|
6
|
+
#
|
7
|
+
# Acting on {AugeasElement} means it expects a Hash `e`
|
8
|
+
# containing `e[:key]` and `e[:value]`.
|
9
|
+
#
|
10
|
+
# It is used with the `&` syntax which makes the matcher
|
11
|
+
# act like a block/lambda/Proc (via {Matcher#to_proc}).
|
12
|
+
#
|
13
|
+
# @note The coupling to {AugeasTree}, {AugeasElement} is not a goal.
|
14
|
+
# Once we have more parsers it will go away.
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
# elements = [
|
18
|
+
# {key: "#comment[]", value: "\"magical\" mostly works"},
|
19
|
+
# {key: "DRIVE", value: "magical"},
|
20
|
+
# {key: "#comment[]", value: "'years' or 'centuries'"},
|
21
|
+
# {key: "PRECISION", value: "years"}
|
22
|
+
# ]
|
23
|
+
# drive_matcher = Matcher.new(key: "DRIVE")
|
24
|
+
# i = elements.index(&drive_matcher) # => 1
|
5
25
|
class Matcher
|
6
|
-
#
|
26
|
+
# The constructor arguments are constraints to match on an element.
|
27
|
+
# All constraints are optional.
|
28
|
+
# All supplied constraints must match, so it is a conjunction.
|
29
|
+
# @param key [Object,nil] if non-nil,
|
30
|
+
# constrain to elements with the name "*key*"
|
31
|
+
# @param collection [Object,nil] if non-nil,
|
32
|
+
# constrain to elements with the name "*collection*[]"
|
33
|
+
# @param value_matcher [Object,Regexp,nil] if non-nil,
|
34
|
+
# constrain to elements whose value is Object or matches Regexp
|
35
|
+
# @yieldparam blk_key [Object]
|
36
|
+
# @yieldparam blk_value [Object]
|
37
|
+
# @yieldreturn [Boolean] if the block is present,
|
38
|
+
# constrain to elements for which the block(*blk_key*, *blk_value*)
|
39
|
+
# returns true
|
7
40
|
def initialize(key: nil, collection: nil, value_matcher: nil, &block)
|
8
41
|
@matcher = lambda do |element|
|
9
42
|
return false unless key_match?(element, key)
|
@@ -14,10 +47,13 @@ module CFA
|
|
14
47
|
end
|
15
48
|
end
|
16
49
|
|
50
|
+
# @return [Proc{AugeasElement=>Boolean}]
|
17
51
|
def to_proc
|
18
52
|
@matcher
|
19
53
|
end
|
20
54
|
|
55
|
+
private
|
56
|
+
|
21
57
|
def key_match?(element, key)
|
22
58
|
return true unless key
|
23
59
|
|
data/lib/cfa/placer.rb
CHANGED
@@ -1,6 +1,21 @@
|
|
1
1
|
module CFA
|
2
|
-
#
|
3
|
-
|
2
|
+
# Places a new {AugeasElement} into an {AugeasTree}.
|
3
|
+
# @abstract Subclasses implement different ways **where**
|
4
|
+
# to place the entry by overriding {#new_element}.
|
5
|
+
class Placer
|
6
|
+
# @param [AugeasTree] tree
|
7
|
+
# @return [AugeasElement,Hash] the new element; it is empty!
|
8
|
+
# Note that the return value is actually a Hash; {AugeasElement}
|
9
|
+
# documents its structure.
|
10
|
+
def new_element(_tree)
|
11
|
+
raise NotImplementedError,
|
12
|
+
"Subclasses of #{Module.nesting.first} must override #{__method__}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Places the new element at the end of the tree.
|
17
|
+
class AppendPlacer < Placer
|
18
|
+
# (see Placer#new_element)
|
4
19
|
def new_element(tree)
|
5
20
|
res = {}
|
6
21
|
tree.data << res
|
@@ -9,14 +24,18 @@ module CFA
|
|
9
24
|
end
|
10
25
|
end
|
11
26
|
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
|
27
|
+
# Finds a specific element using a {Matcher} and places the new element
|
28
|
+
# **before** it. Appends at the end if a match is not found.
|
29
|
+
#
|
30
|
+
# Useful when a config option should be inserted to a specific location,
|
31
|
+
# or when assigning a comment to an option.
|
32
|
+
class BeforePlacer < Placer
|
33
|
+
# @param [Matcher] matcher
|
16
34
|
def initialize(matcher)
|
17
35
|
@matcher = matcher
|
18
36
|
end
|
19
37
|
|
38
|
+
# (see Placer#new_element)
|
20
39
|
def new_element(tree)
|
21
40
|
index = tree.data.index(&@matcher)
|
22
41
|
|
@@ -30,14 +49,17 @@ module CFA
|
|
30
49
|
end
|
31
50
|
end
|
32
51
|
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
|
52
|
+
# Finds a specific element using a {Matcher} and places the new element
|
53
|
+
# **after** it. Appends at the end if a match is not found.
|
54
|
+
#
|
55
|
+
# Useful when a config option should be inserted to a specific location.
|
56
|
+
class AfterPlacer < Placer
|
57
|
+
# @param [Matcher] matcher
|
37
58
|
def initialize(matcher)
|
38
59
|
@matcher = matcher
|
39
60
|
end
|
40
61
|
|
62
|
+
# (see Placer#new_element)
|
41
63
|
def new_element(tree)
|
42
64
|
index = tree.data.index(&@matcher)
|
43
65
|
|
@@ -51,15 +73,18 @@ module CFA
|
|
51
73
|
end
|
52
74
|
end
|
53
75
|
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
|
76
|
+
# Finds a specific element using a {Matcher} and **replaces** it
|
77
|
+
# with the new element. Appends at the end if a match is not found.
|
78
|
+
#
|
79
|
+
# Useful in key-value configuration files where a specific key
|
80
|
+
# needs to be assigned.
|
81
|
+
class ReplacePlacer < Placer
|
82
|
+
# @param [Matcher] matcher
|
59
83
|
def initialize(matcher)
|
60
84
|
@matcher = matcher
|
61
85
|
end
|
62
86
|
|
87
|
+
# (see Placer#new_element)
|
63
88
|
def new_element(tree)
|
64
89
|
index = tree.data.index(&@matcher)
|
65
90
|
res = {}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cfa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josef Reidinger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-11-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby-augeas
|