unixconfigstyle 1.0.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.
@@ -0,0 +1,418 @@
1
+ ###############################################################################
2
+ ## Author: Erwan SEITE
3
+ ## Aim: Read or Write config files written in Unix Style
4
+ ## Licence : GPL v2
5
+ ## Source : https://github.com/wanix/ruby-UnixConfigStyle
6
+ ## The section name "[-UnixConfigStyle-]" is reserved for the global one
7
+ ###############################################################################
8
+ class UnixConfigStyle
9
+
10
+ Version = '1.0'
11
+
12
+ @@rootsection="[-UnixConfigStyle-]"
13
+
14
+ @@regexpStruct={}
15
+ #Empty line definition
16
+ @@regexpStruct[:emptyline] = /^\s*$/
17
+ #Comment line definition
18
+ @@regexpStruct[:commentline] = /^\s*[#;]/
19
+ #Section Line definition
20
+ @@regexpStruct[:sectionline] = /^\s*\[(.+?)\]\s*([#;].*)?$/
21
+ #Parameter line definition
22
+ @@regexpStruct[:paramline] = /^\s*([\d\w\-]+)\s*=.*$/
23
+ @@regexpStruct[:paramlinequote] = /^\s*([\d\w\-]+)\s*=\s*('.*')\s*([#;].*)?$/
24
+ @@regexpStruct[:paramline2quote] = /^\s*([\d\w\-]+)\s*=\s*(".*")\s*([#;].*)?$/
25
+ @@regexpStruct[:paramlinenormal] = /^\s*([\d\w\-]+)\s*=\s*(.*?)\s*([#;].*)?$/
26
+
27
+ #(private) Initialise the class and read the file
28
+ #Parameters:
29
+ # config_file: String (path to a readable unix config file) (optionnal)
30
+ def initialize(config_file=nil)
31
+ @sections = {}
32
+
33
+ if(config_file)
34
+ push_unix_config_file(config_file)
35
+ end
36
+ end #initialize
37
+ private :initialize
38
+
39
+ #(private) Validate a file is readable
40
+ #Parameters:
41
+ # fileToRead: String (path to a readable file)
42
+ def validate(fileToRead)
43
+ unless File.readable?(fileToRead)
44
+ raise Errno::EACCES, "Can't read #{fileToRead}"
45
+ end
46
+ end #validate
47
+ private :validate
48
+
49
+ #Read a config file and add its properties to the end of the object ones
50
+ #Parameters:
51
+ # config_file: String (path to a readable unix config file)
52
+ def push_unix_config_file(config_file)
53
+ add_unix_config_file(config_file,"push")
54
+ end #push_unix_config_file
55
+
56
+ #Read a config file and add its properties to the start of the object ones
57
+ #Parameters:
58
+ # config_file: String (path to a readable unix config file)
59
+ def insert_unix_config_file(config_file)
60
+ add_unix_config_file(config_file,"insert")
61
+ end #insert_unix_config_file
62
+
63
+ #(private) read a config file and add its properties to the current object
64
+ #Parameters:
65
+ # config_file: String (path to a readable unix config file)
66
+ # operation: String [push|insert]
67
+ def add_unix_config_file(config_file, operation="push")
68
+ if operation != "push" and operation != "insert"
69
+ raise ArgumentError, "operation #{operation} not allowed", caller
70
+ end
71
+ validate(config_file)
72
+
73
+ file = File.open(config_file, 'r')
74
+
75
+ @sections[@@rootsection]={} unless @sections.key?(@@rootsection)
76
+ currentSection=@@rootsection
77
+
78
+ while !file.eof?
79
+ line = file.readline
80
+ #We ignore the empty lines
81
+ next if @@regexpStruct[:emptyline].match(line)
82
+ #We ignore the comment lines
83
+ next if @@regexpStruct[:commentline].match(line)
84
+ #Change the current section if a new line section is matched
85
+ sectionmatch = @@regexpStruct[:sectionline].match(line)
86
+ if sectionmatch
87
+ currentSection=sectionmatch[1]
88
+ #If this section is seen for the first time, initialise the hash
89
+ @sections[currentSection]={} unless @sections.key?(currentSection)
90
+ next
91
+ end
92
+ #Now we have to recognize the line or there is an error in the file ... or a bug here :)
93
+ paramlinematch = @@regexpStruct[:paramline].match(line)
94
+ if paramlinematch
95
+ #First time this param is seen ?
96
+ @sections[currentSection][paramlinematch[1]]=[] unless @sections[currentSection].key?(paramlinematch[1])
97
+ parammatch = @@regexpStruct[:paramlinequote].match(line)
98
+ if parammatch
99
+ if operation == "push"
100
+ @sections[currentSection][paramlinematch[1]].push(parammatch[2])
101
+ elsif operation == "insert"
102
+ @sections[currentSection][paramlinematch[1]].insert(0,parammatch[2])
103
+ end
104
+ next
105
+ end
106
+ parammatch = @@regexpStruct[:paramline2quote].match(line)
107
+ if parammatch
108
+ if operation == "push"
109
+ @sections[currentSection][paramlinematch[1]].push(parammatch[2])
110
+ elsif operation == "insert"
111
+ @sections[currentSection][paramlinematch[1]].insert(0,parammatch[2])
112
+ end
113
+ next
114
+ end
115
+ parammatch = @@regexpStruct[:paramlinenormal].match(line)
116
+ if parammatch
117
+ if operation == "push"
118
+ @sections[currentSection][paramlinematch[1]].push(parammatch[2])
119
+ elsif operation == "insert"
120
+ @sections[currentSection][paramlinematch[1]].insert(0,parammatch[2])
121
+ end
122
+ next
123
+ end
124
+ else
125
+ warn("[warning] unrecognized line "+file.lineno.to_s+" in "+@unix_config_file+" : "+line)
126
+ end
127
+ end
128
+ file.close()
129
+ end
130
+ private :add_unix_config_file
131
+
132
+ #Write the object in a file
133
+ #Parameters:
134
+ # fileToWrite : String, path to a file
135
+ # comment: String (optionnal)
136
+ def write (fileToWrite, comment=nil)
137
+ File.open(fileToWrite,'w') do |file|
138
+ self.print(comment, file)
139
+ end
140
+ end #def write
141
+
142
+ #Print the object in a unix config style into an IO obj
143
+ #Parameters:
144
+ # comment: String
145
+ # io_obj : IO (default stdout)
146
+ def print (comment=nil, io_obj=$stdout)
147
+ raise ArgumentError, 'the argument "comment" must be a String' unless (comment.is_a? String or comment == nil)
148
+ raise ArgumentError, 'the argument "io_obj" must be an IO class or an IO inherited class' unless io_obj.is_a? IO
149
+ if comment
150
+ io_obj.puts "##{comment}"
151
+ end
152
+ if @sections.key?(@@rootsection)
153
+ @sections[@@rootsection].keys.each do |param_key|
154
+ @sections[@@rootsection][param_key].each do |param_value|
155
+ io_obj.puts "#{param_key}=#{param_value}"
156
+ end
157
+ end
158
+ end
159
+ @sections.keys.each do |section_key|
160
+ if section_key == @@rootsection
161
+ next
162
+ end
163
+ io_obj.puts "[#{section_key}]"
164
+ @sections[section_key].keys.each do |param_key|
165
+ @sections[section_key][param_key].each do |param_value|
166
+ io_obj.puts "#{param_key}=#{param_value}"
167
+ end
168
+ end
169
+ end
170
+ end #def print
171
+
172
+ #Get all avalaibles sections (all but root one)
173
+ #return an array
174
+ def getSections ()
175
+ allsections = @sections.keys
176
+ if allsections
177
+ allsections.delete(@@rootsection)
178
+ end
179
+ return allsections
180
+ end #def getSections
181
+
182
+ #Get all avalaibles keys for this section
183
+ #return an array (or nil if no keys found)
184
+ #Parameters:
185
+ # section: String (optionnal)
186
+ def getKeys (section=@@rootsection)
187
+ if @sections.key?(section)
188
+ return @sections[section].keys
189
+ end
190
+ return nil
191
+ end #def getKeys
192
+
193
+ #Get all differents keys in the object
194
+ # if section is defined, return a merged array for keys in the section and keys in root section
195
+ # if section is not defined, return a a merged array for all keys in the object
196
+ #return an array (or nil if no keys found)
197
+ def getAllKeys (section=nil)
198
+ allKeys=[]
199
+ #Get keys from root section
200
+ allKeys.concat(@sections[@@rootsection].keys) if @sections.key?(@@rootsection)
201
+ if ( section == nil )
202
+ #Get keys from the others sections if exists and are not empty
203
+ if self.haveSections?()
204
+ self.getSections().each do |subsection|
205
+ allKeys.concat(@sections[subsection].keys) if @sections.key?(subsection)
206
+ end
207
+ end
208
+ else
209
+ #get keys for this specific section
210
+ allKeys.concat(@sections[section].keys) if self.sectionExists?(section)
211
+ end
212
+ return nil if allKeys.empty?()
213
+ allKeys.uniq!
214
+ return allKeys
215
+ end #getAllKeys
216
+
217
+ #Add values for a key
218
+ #Parameters:
219
+ # values: Array or String
220
+ # key: String
221
+ # section: String (optionnal)
222
+ def addValues (values, key, section=@@rootsection)
223
+ @sections[section]={} unless @sections.key?(section)
224
+ @sections[section][key]=[] unless @sections[section].key?(key)
225
+ if values.is_a? Array
226
+ return true if @sections[section][key].concat(values)
227
+ else
228
+ #String
229
+ return true if @sections[section][key].push(values)
230
+ end
231
+ return false
232
+ end #def addValues
233
+
234
+ #Insert values for a key
235
+ #Parameters:
236
+ # values: Array or String
237
+ # key: String
238
+ # section: String (optionnal)
239
+ def insertValues (values, key, section=@@rootsection)
240
+ @sections[section]={} unless @sections.key?(section)
241
+ @sections[section][key]=[] unless @sections[section].key?(key)
242
+ if @sections[section][key].insert(0,values)
243
+ return true
244
+ else
245
+ return false
246
+ end
247
+ end #insertValues
248
+
249
+ #Get all values for a key (in a section if given, else in root one)
250
+ #Parameters:
251
+ # key: String
252
+ # section: String (optionnal)
253
+ # globalSearch: boolean, if true, insert the results from the root section (default false)
254
+ def getValues (key, section=@@rootsection, globalSearch=false)
255
+ resultArray=[]
256
+ if (globalSearch == true and section != @@rootsection)
257
+ #We put first the result form the root section
258
+ resultArray.concat(@sections[@@rootsection][key]) if ( @sections.key?(@@rootsection) and @sections[@@rootsection].key?(key) )
259
+ end
260
+ resultArray.concat(@sections[section][key]) if ( @sections.key?(section) and @sections[section].key?(key) )
261
+ return nil if resultArray.empty?()
262
+ return resultArray
263
+ end #getValues
264
+
265
+ #Get the first value for a key (config first win)
266
+ #Parameters:
267
+ # key: String
268
+ # section: String (optionnal)
269
+ def getFirstValue (key, section=@@rootsection)
270
+ if @sections.key?(section)
271
+ if @sections[section].key?(key)
272
+ return @sections[section][key].first
273
+ end
274
+ end
275
+ return nil
276
+ end #getFirstValue
277
+
278
+ #Get the last value for a key (config last win)
279
+ #Parameters:
280
+ # key: String
281
+ # section: String (optionnal)
282
+ def getLastValue (key, section=@@rootsection)
283
+ if @sections.key?(section)
284
+ if @sections[section].key?(key)
285
+ return @sections[section][key].last
286
+ end
287
+ end
288
+ return nil
289
+ end #getLastValue
290
+
291
+ #Get the value with the given index for a key
292
+ #Parameters:
293
+ # key: String
294
+ # index :Integer (default 0)
295
+ # section: String (optionnal)
296
+ def getValue (key, index=0, section=@@rootsection)
297
+ if @sections.key?(section)
298
+ if @sections[section].key?(key)
299
+ return @sections[section][key][index]
300
+ end
301
+ end
302
+ return nil
303
+ end #getValue
304
+
305
+ #Replace the first value by the given one
306
+ #Parameters:
307
+ # newvalue : string
308
+ # key: String
309
+ # section: String (optionnal)
310
+ def replaceFirstValue (newvalue, key, section=@@rootsection)
311
+ if @sections.key?(section)
312
+ if @sections[section].key?(key)
313
+ @sections[section][key].first.replace(newvalue)
314
+ end
315
+ end
316
+ return nil
317
+ end #replaceFirstValue
318
+
319
+ #Replace the last value by the given one
320
+ #Parameters:
321
+ # newvalue : string
322
+ # key: String
323
+ # section: String (optionnal)
324
+ def replaceLastValue (newvalue, key, section=@@rootsection)
325
+ if @sections.key?(section)
326
+ if @sections[section].key?(key)
327
+ @sections[section][key].last.replace(newvalue)
328
+ end
329
+ end
330
+ return nil
331
+ end #replaceLastValue
332
+
333
+ #Replace the value by the given one
334
+ #Parameters:
335
+ # newvalue : string
336
+ # key: String
337
+ # index :Integer (default 0)
338
+ # section: String (optionnal)
339
+ def replaceValue (newvalue, key, index=0, section=@@rootsection)
340
+ if @sections.key?(section)
341
+ if @sections[section].key?(key)
342
+ @sections[section][key][index].replace(newvalue)
343
+ end
344
+ end
345
+ return nil
346
+ end #replaceValue
347
+
348
+ #Replace all the value array by the given one
349
+ #Parameters:
350
+ # newvalues : Array
351
+ # key: String
352
+ # section: String (optionnal)
353
+ def replaceValues (newvalues, key, section=@@rootsection)
354
+ if @sections.key?(section)
355
+ if @sections[section].key?(key)
356
+ @sections[section][key].replace(newvalues)
357
+ end
358
+ end
359
+ return nil
360
+ end #replaceValues
361
+
362
+ #Return true if the key exists for the section "section"
363
+ #if global search is set to true, return true if the key exists in the root section and not in the section itself
364
+ #Parameters:
365
+ # key : string, the key to search
366
+ # section: string, the section where to search the key (default the root one)
367
+ # globalSearch: boolean, if the section is not the root one, return true if the key is found in the root section even if it not exists in the given section
368
+ def keyExists?(key, section, globalSearch=false)
369
+ return false if @sections.empty?
370
+ if ( section == nil)
371
+ return false unless @sections.has_key?(@@rootsection)
372
+ return @sections[@@rootsection].has_key?(key)
373
+ else
374
+ return false unless @sections.has_key?(section)
375
+ if (globalSearch == true and @sections.has_key?(@@rootsection))
376
+ return ( @sections[section].has_key?(key) || @sections[@@rootsection].has_key?(key) )
377
+ else
378
+ return @sections[section].has_key?(key)
379
+ end
380
+ end
381
+ end
382
+
383
+ #Return true if the specific section is found
384
+ def sectionExists? (section)
385
+ return false if section == nil
386
+ return false if @sections.empty?
387
+ return @sections.has_key?(section)
388
+ end
389
+
390
+ #Return true if at list one key is present
391
+ def haveKeys? (section=@@rootsection)
392
+ return false if @sections.empty?
393
+ return true unless @sections[section].empty?
394
+ return false
395
+ end #haveKeys?
396
+
397
+ #Return true if at list one section is present
398
+ def haveSections? ()
399
+ return true unless self.getSections().empty?
400
+ return false
401
+ end #haveSections?
402
+
403
+ #Return false if at list one key is found, whatever its section, global or not
404
+ def isEmpty?()
405
+ return false if self.haveKeys?
406
+ if self.haveSections?
407
+ self.getSections().each do |section|
408
+ return false if self.haveKeys?(section)
409
+ end
410
+ end
411
+ return true
412
+ end #isEmpty?()
413
+
414
+ #Return the root section name (for loops with sections?)
415
+ def getRootSectionName
416
+ return @@rootsection
417
+ end
418
+ end
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env rspec
2
+ ###############################################################################
3
+ ## Author: Erwan SEITE
4
+ ## Aim: Read or Write config files written in Unix Style
5
+ ## Licence : GPL v2
6
+ ## Source : https://github.com/wanix/ruby-UnixConfigStyle
7
+ ## Help : http://betterspecs.org/fr/
8
+ ###############################################################################
9
+ require 'rspec'
10
+ $: << File.join(File.dirname(__FILE__), "..", "lib")
11
+ require 'unixconfigstyle.rb'
12
+
13
+ describe 'ruby-UnixConfigStyle' do
14
+
15
+ unix_config_file1=File.dirname(__FILE__)+"/configfiles/conf_unix1.cfg"
16
+ context "The file "+unix_config_file1+" should be parsed" do
17
+ it "Should give you an array of sections (Section1, Section2, newsection)" do
18
+ objUnixConfFile1 = UnixConfigStyle.new(unix_config_file1)
19
+ objUnixConfFile1.getSections().should eq(["Section1","Section2","newsection"])
20
+ end
21
+ end
22
+ end
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: unixconfigstyle
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Erwan SEITE
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-05-15 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: ! " This library manage config file written in Unix style\n Can manage
15
+ multi-values, concat multiple files, use it as a config object (see easyfpm)\n"
16
+ email: wanix.fr@gmail.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/unixconfigstyle.rb
22
+ - tests/test-unixconfigstyle.rb
23
+ homepage: https://github.com/wanix/ruby-UnixConfigStyle
24
+ licenses:
25
+ - GPLv2
26
+ post_install_message:
27
+ rdoc_options: []
28
+ require_paths:
29
+ - lib
30
+ required_ruby_version: !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ! '>='
34
+ - !ruby/object:Gem::Version
35
+ version: 1.8.7
36
+ required_rubygems_version: !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ! '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ requirements: []
43
+ rubyforge_project:
44
+ rubygems_version: 1.8.23
45
+ signing_key:
46
+ specification_version: 3
47
+ summary: Parse, Write and manage config files in Unix Format
48
+ test_files:
49
+ - tests/test-unixconfigstyle.rb