pythonconfig 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ === 1.0.0 / 2009-03-28
2
+
3
+ * First release
4
+
5
+ * Multiple sections are parsed
6
+ * Interpolation using %(key) supported
7
+ * Multiline values supported
@@ -0,0 +1,7 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ bin/pythonconfig
6
+ lib/pythonconfig.rb
7
+ test/test_pythonconfig.rb
@@ -0,0 +1,95 @@
1
+ = pythonconfig
2
+
3
+ * http://www.carboni.ca/
4
+
5
+ == DESCRIPTION:
6
+
7
+ Class for parsing and writing Python configuration files created by the
8
+ ConfigParser classes in Python. These files are structured like this:
9
+ [Section Name]
10
+ key = value
11
+ otherkey: othervalue
12
+
13
+ [Other Section]
14
+ key: value3
15
+ otherkey = value4
16
+
17
+ Leading whitespace before values are trimmed, and the key must be the at the
18
+ start of the line - no leading whitespace there. You can use : or = .
19
+
20
+ Multiline values are supported, as long as the second (or third, etc.) lines
21
+ start with whitespace:
22
+
23
+ [Section]
24
+ bigstring: This is a very long string, so I'm not sure I'll be
25
+ able to fit it on one line, but as long as
26
+ there is one space before each line, I'm ok. Tabs work too.
27
+
28
+ Also, this class supports interpolation:
29
+ [Awards]
30
+ output: Congratulations for winning %(prize)!
31
+ prize: the lottery
32
+ Will result in:
33
+ config.sections["Awards"]["output"] == "Congratulations for winning the lottery!"
34
+
35
+ You can also access the sections with the dot operator, but only with all-lowercase:
36
+ [Awards]
37
+ key:value
38
+ [prizes]
39
+ lottery=3.2 million
40
+
41
+ config.awards["key"] #=> "value"
42
+ config.prizes["lottery"] #=> "3.2 million"
43
+
44
+ You can modify any values you want, though to add sections, you should use the add_section
45
+ method.
46
+ config.sections["prizes"]["lottery"] = "100 dollars" # someone hit the jackpot
47
+ config.add_section("Candies")
48
+ config.candies["green"] = "tasty"
49
+ When you want to output a configuration, just call its +to_s+ method.
50
+ File.open("output.ini","w") do |out|
51
+ out.write config.to_s
52
+ end
53
+
54
+ == FEATURES/PROBLEMS:
55
+
56
+ * Multiple sections are parsed
57
+ * Interpolation using %(key) supported
58
+ * Multiline values supported
59
+
60
+ == SYNOPSIS:
61
+
62
+ See the Description.
63
+
64
+ == REQUIREMENTS:
65
+
66
+ * none
67
+
68
+ == INSTALL:
69
+
70
+ * sudo gem install pythonconfig
71
+
72
+ == LICENSE:
73
+
74
+ (The MIT License)
75
+
76
+ Copyright (c) 2009 FIX
77
+
78
+ Permission is hereby granted, free of charge, to any person obtaining
79
+ a copy of this software and associated documentation files (the
80
+ 'Software'), to deal in the Software without restriction, including
81
+ without limitation the rights to use, copy, modify, merge, publish,
82
+ distribute, sublicense, and/or sell copies of the Software, and to
83
+ permit persons to whom the Software is furnished to do so, subject to
84
+ the following conditions:
85
+
86
+ The above copyright notice and this permission notice shall be
87
+ included in all copies or substantial portions of the Software.
88
+
89
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
90
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
91
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
92
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
93
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
94
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
95
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,12 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ require './lib/pythonconfig.rb'
6
+
7
+ Hoe.new('pythonconfig', PythonConfig::VERSION) do |p|
8
+ # p.rubyforge_name = 'pythonconfigx' # if different than lowercase project name
9
+ p.developer('FIX', 'FIX@example.com')
10
+ end
11
+
12
+ # vim: syntax=Ruby
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ abort "you need to write me"
@@ -0,0 +1,156 @@
1
+ require 'delegate'
2
+ # = PythonConfig
3
+ # Class for parsing and writing Python configuration files created by the
4
+ # ConfigParser classes in Python. These files are structured like this:
5
+ # [Section Name]
6
+ # key = value
7
+ # otherkey: othervalue
8
+ #
9
+ # [Other Section]
10
+ # key: value3
11
+ # otherkey = value4
12
+ #
13
+ # Leading whitespace before values are trimmed, and the key must be the at the
14
+ # start of the line - no leading whitespace there. You can use : or = .
15
+ #
16
+ # Multiline values are supported, as long as the second (or third, etc.) lines
17
+ # start with whitespace:
18
+ #
19
+ # [Section]
20
+ # bigstring: This is a very long string, so I'm not sure I'll be
21
+ # able to fit it on one line, but as long as
22
+ # there is one space before each line, I'm ok. Tabs work too.
23
+ #
24
+ # Also, this class supports interpolation:
25
+ # [Awards]
26
+ # output: Congratulations for winning %(prize)!
27
+ # prize: the lottery
28
+ # Will result in:
29
+ # config.sections["Awards"]["output"] == "Congratulations for winning the lottery!"
30
+ #
31
+ # You can also access the sections with the dot operator, but only with all-lowercase:
32
+ # [Awards]
33
+ # key:value
34
+ # [prizes]
35
+ # lottery=3.2 million
36
+ #
37
+ # config.awards["key"] #=> "value"
38
+ # config.prizes["lottery"] #=> "3.2 million"
39
+ #
40
+ # You can modify any values you want, though to add sections, you should use the add_section
41
+ # method.
42
+ # config.sections["prizes"]["lottery"] = "100 dollars" # someone hit the jackpot
43
+ # config.add_section("Candies")
44
+ # config.candies["green"] = "tasty"
45
+ # When you want to output a configuration, just call its +to_s+ method.
46
+ # File.open("output.ini","w") do |out|
47
+ # out.write config.to_s
48
+ # end
49
+ module PythonConfig
50
+ VERSION = '1.0.0'
51
+ MAX_INTERPOLATION_DEPTH = 200
52
+ # Don't make recursive interpolating values!
53
+ class InterpolationTooDeepError < StandardError; end
54
+ # This is the main class that handles configurations. You parse, modify, and output
55
+ # through this class. See the README for tons of examples.
56
+ class ConfigParser
57
+ attr_reader :sections
58
+
59
+ SECTION_REGEXP = /\[([^\[\]]*)\]/
60
+ ASSIGNMENT_REGEXP = /([^:=\s]+)\s*[:=]\s*([^\n]*?)$/
61
+ LONG_HEADER_REGEXP = /^([ \t]+)([^\n]+)$/
62
+ # Creates a new ConfigParser. If +io+ is provided, the configuraiton file is read
63
+ # from the io.
64
+ def initialize(io = nil)
65
+ @sections = {}
66
+ io.each do |line|
67
+ parse_line line
68
+ end unless io.nil?
69
+ end
70
+
71
+ def parse_line line #:nodoc:
72
+
73
+ if line =~ SECTION_REGEXP
74
+ section_name = $1
75
+ @cursection = add_section section_name
76
+ elsif line =~ ASSIGNMENT_REGEXP
77
+ @cursection[$1] = $2
78
+ @cur_assignment = $1
79
+ elsif line =~ LONG_HEADER_REGEXP
80
+ @cursection[@cur_assignment] += " " + $2
81
+ end
82
+ end
83
+
84
+ # Returns the names of all the sections, which can be used for keys into the sections
85
+ def section_names
86
+ @sections.keys
87
+ end
88
+
89
+ # Creates a new section, with the values as provided by the (optional) values parameter
90
+ def add_section(section_name, values={})
91
+ newsection = ConfigSection.new(values)
92
+ @sections[section_name] = newsection
93
+ self.instance_eval %Q{
94
+ def #{section_name.downcase}
95
+ @sections["#{section_name}"]
96
+ end
97
+ }
98
+ newsection
99
+ end
100
+
101
+ # Returns the section given by +section+
102
+ def [](section)
103
+ @sections[section]
104
+ end
105
+
106
+ # Returns the configuration as a string that can be output to a file. Does not perform
107
+ # interpolation before writing.
108
+ def to_s
109
+ output = ""
110
+ @sections.each do |k,v|
111
+ output << "[#{k}]\n"
112
+ output << v.to_s
113
+ end
114
+ output
115
+ end
116
+
117
+ end
118
+ # = ConfigSection
119
+ # This is a simple section in a config document - treat it exactly like a hash,
120
+ # whose keys are the keys in the config, and whose value are the values in the config.
121
+ #
122
+ # This is a separate class entirely because it has to handle the magical interpolation
123
+ # that allows this ini file:
124
+ # [Awards]
125
+ # output: Congratulations for winning %(prize)!
126
+ # prize: the lottery
127
+ # To result in:
128
+ # config.sections["Awards"]["output"] == "Congratulations for winning the lottery!"
129
+ #
130
+ class ConfigSection < DelegateClass(Hash)
131
+ def initialize(source)
132
+ @source_hash = source
133
+ super(@source_hash)
134
+ end
135
+ def [](key) #:nodoc:
136
+ str = @source_hash[key]
137
+ interpolate(str)
138
+ end
139
+
140
+ def interpolate(str, cur_depth=0) #:nodoc:
141
+ raise InterpolationTooDeepError.new("Interpolation too deep!") if cur_depth > PythonConfig::MAX_INTERPOLATION_DEPTH
142
+ nextval = str
143
+ nextval = str.gsub(/\%\((.*)\)/,@source_hash[$1]) if str =~ /%\((.*)\)/
144
+ nextval = interpolate(nextval,cur_depth+1) if nextval =~ /%\((.*)\)/
145
+ nextval
146
+ end
147
+
148
+ def to_s #:nodoc:
149
+ output = ""
150
+ @source_hash.each do |k,v|
151
+ output << "#{k} = #{v.gsub(/\n/,"\n ")}" << "\n"
152
+ end
153
+ output
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,82 @@
1
+ require "test/unit"
2
+ require "pythonconfig"
3
+
4
+ class TestConfigParser < Test::Unit::TestCase
5
+ include PythonConfig
6
+ def test_sections
7
+ cfg = nil
8
+ File.open(File.join(File.dirname(__FILE__),"inputfile.ini"), "r") do |inp|
9
+ cfg = ConfigParser.new(inp)
10
+ end
11
+ assert_equal(["cool_section", "evil", "other_stuff"],cfg.sections.keys.sort)
12
+ end
13
+
14
+ def test_basic_assignments
15
+ cfg = nil
16
+ File.open(File.join(File.dirname(__FILE__),"inputfile.ini"), "r") do |inp|
17
+ cfg = ConfigParser.new(inp)
18
+ end
19
+ assert_equal("true",cfg.sections["cool_section"]["lame"])
20
+ assert_equal("8.7",cfg.sections["other_stuff"]["sweetness"])
21
+ assert_equal("false",cfg.sections["cool_section"]["cool"])
22
+ end
23
+
24
+ def test_multiline
25
+ cfg = nil
26
+ File.open(File.join(File.dirname(__FILE__),"inputfile.ini"), "r") do |inp|
27
+ cfg = ConfigParser.new(inp)
28
+ end
29
+ assert_equal("super good stuff that i bet you didn't think was possible did you now?", cfg.sections["cool_section"]["multiline"])
30
+ end
31
+
32
+ def test_dot_accessor
33
+ cfg = nil
34
+ File.open(File.join(File.dirname(__FILE__),"inputfile.ini"), "r") do |inp|
35
+ cfg = ConfigParser.new(inp)
36
+ end
37
+ assert_equal(cfg.sections["cool_section"], cfg.cool_section)
38
+ end
39
+
40
+ def test_array_accessor
41
+ cfg = nil
42
+ File.open(File.join(File.dirname(__FILE__),"inputfile.ini"), "r") do |inp|
43
+ cfg = ConfigParser.new(inp)
44
+ end
45
+ assert_equal(cfg.sections["cool_section"], cfg["cool_section"])
46
+ end
47
+
48
+ def test_allow_empty
49
+ cfg = nil
50
+ File.open(File.join(File.dirname(__FILE__),"inputfile.ini"), "r") do |inp|
51
+ cfg = ConfigParser.new(inp)
52
+ end
53
+ assert_equal("", cfg.sections["cool_section"]["empty"])
54
+ end
55
+
56
+ def test_interpolation
57
+ cfg = nil
58
+ File.open(File.join(File.dirname(__FILE__),"inputfile.ini"), "r") do |inp|
59
+ cfg = ConfigParser.new(inp)
60
+ end
61
+ assert_equal("your sweetness is 8.7!", cfg.sections["other_stuff"]["output"])
62
+ end
63
+
64
+ def test_interpolation_recursion_exception
65
+ cfg = nil
66
+ File.open(File.join(File.dirname(__FILE__),"inputfile.ini"), "r") do |inp|
67
+ cfg = ConfigParser.new(inp)
68
+ end
69
+ assert_raises InterpolationTooDeepError do
70
+ cfg.sections["evil"]["firstone"]
71
+ end
72
+ end
73
+
74
+ def test_add_section
75
+ cfg = nil
76
+ File.open(File.join(File.dirname(__FILE__),"inputfile.ini"), "r") do |inp|
77
+ cfg = ConfigParser.new(inp)
78
+ end
79
+ cfg.add_section "new_section"
80
+ assert_equal(["cool_section", "evil","new_section", "other_stuff"],cfg.sections.keys.sort)
81
+ end
82
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pythonconfig
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - FIX
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-28 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hoe
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.11.0
24
+ version:
25
+ description: "Class for parsing and writing Python configuration files created by the ConfigParser classes in Python. These files are structured like this: [Section Name] key = value otherkey: othervalue [Other Section] key: value3 otherkey = value4 Leading whitespace before values are trimmed, and the key must be the at the start of the line - no leading whitespace there. You can use : or = . Multiline values are supported, as long as the second (or third, etc.) lines start with whitespace: [Section] bigstring: This is a very long string, so I'm not sure I'll be able to fit it on one line, but as long as there is one space before each line, I'm ok. Tabs work too. Also, this class supports interpolation: [Awards] output: Congratulations for winning %(prize)! prize: the lottery Will result in: config.sections[\"Awards\"][\"output\"] == \"Congratulations for winning the lottery!\" You can also access the sections with the dot operator, but only with all-lowercase: [Awards] key:value [prizes] lottery=3.2 million config.awards[\"key\"] #=> \"value\" config.prizes[\"lottery\"] #=> \"3.2 million\" You can modify any values you want, though to add sections, you should use the add_section method. config.sections[\"prizes\"][\"lottery\"] = \"100 dollars\" # someone hit the jackpot config.add_section(\"Candies\") config.candies[\"green\"] = \"tasty\" When you want to output a configuration, just call its +to_s+ method. File.open(\"output.ini\",\"w\") do |out| out.write config.to_s end"
26
+ email:
27
+ - FIX@example.com
28
+ executables:
29
+ - pythonconfig
30
+ extensions: []
31
+
32
+ extra_rdoc_files:
33
+ - History.txt
34
+ - Manifest.txt
35
+ - README.txt
36
+ files:
37
+ - History.txt
38
+ - Manifest.txt
39
+ - README.txt
40
+ - Rakefile
41
+ - bin/pythonconfig
42
+ - lib/pythonconfig.rb
43
+ - test/test_pythonconfig.rb
44
+ has_rdoc: true
45
+ homepage: http://www.carboni.ca/
46
+ post_install_message:
47
+ rdoc_options:
48
+ - --main
49
+ - README.txt
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ requirements: []
65
+
66
+ rubyforge_project: pythonconfig
67
+ rubygems_version: 1.3.1
68
+ signing_key:
69
+ specification_version: 2
70
+ summary: Class for parsing and writing Python configuration files created by the ConfigParser classes in Python
71
+ test_files:
72
+ - test/test_pythonconfig.rb