inifile 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,9 @@
1
+ == 0.2.0 / 2009-10-27
2
+
3
+ * 1 minor enhancement
4
+ - Using Mr Bones for rake tasks and gem management
5
+
6
+ == 0.1.0 / 2006-11-26
7
+
8
+ * 1 major enhancement
9
+ * Birthday!
@@ -0,0 +1,20 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/inifile.rb
6
+ tasks/annotations.rake
7
+ tasks/doc.rake
8
+ tasks/gem.rake
9
+ tasks/manifest.rake
10
+ tasks/rubyforge.rake
11
+ tasks/setup.rb
12
+ tasks/svn.rake
13
+ tasks/test.rake
14
+ test/data/bad_1.ini
15
+ test/data/bad_2.ini
16
+ test/data/comment.ini
17
+ test/data/good.ini
18
+ test/data/mixed_comment.ini
19
+ test/data/param.ini
20
+ test/test_inifile.rb
data/README.txt CHANGED
@@ -1,61 +1,98 @@
1
+ = inifile
2
+ by Tim Pease
3
+ http://codeforpeople.rubyforge.org/inifile
1
4
 
2
- = Ruby INI File Parser and Writer
5
+ == DESCRIPTION:
3
6
 
4
- == Introduction
7
+ This is a native Ruby package for reading and writing INI files.
5
8
 
6
- An initialization file, or INI file, is a configuration file that contains
7
- configuration data for Microsoft Windows based applications. Starting with
8
- Windows 95, the INI file format was superseded but not entirely replaced by a
9
- registry database in Microsoft operating systems.
9
+ Although made popular by Windows, INI files can be used on any system thanks
10
+ to their flexibility. They allow a program to store configuration data, which
11
+ can then be easily parsed and changed. Two notable systems that use the INI
12
+ format are Samba and Trac.
13
+
14
+ == SYNOPSIS:
10
15
 
11
- Although made popular by Windows, INI files can be used on any system thanks
12
- to their flexibility. They allow a program to store configuration data, which
13
- can then be easily parsed and changed.
16
+ An initialization file, or INI file, is a configuration file that contains
17
+ configuration data for Microsoft Windows based applications. Starting with
18
+ Windows 95, the INI file format was superseded but not entirely replaced by
19
+ a registry database in Microsoft operating systems.
14
20
 
15
- == File Format
21
+ Although made popular by Windows, INI files can be used on any system thanks
22
+ to their flexibility. They allow a program to store configuration data, which
23
+ can then be easily parsed and changed.
16
24
 
17
- A typical INI file might look like this:
25
+ === File Format
18
26
 
19
- [section1]
27
+ A typical INI file might look like this:
20
28
 
21
- ; some comment on section1
22
- var1 = foo
23
- var2 = doodle
29
+ [section1]
30
+
31
+ ; some comment on section1
32
+ var1 = foo
33
+ var2 = doodle
24
34
 
25
- [section2]
35
+ [section2]
36
+
37
+ ; another comment
38
+ var1 = baz
39
+ var2 = shoodle
40
+
41
+ ==== Format
42
+
43
+ This describes the elements of the INI file format:
44
+
45
+ * *Sections*: Section declarations start with '[' and end with ']' as in [section1] and [section2] above. And sections start with section declarations.
46
+ * *Parameters*: The "var1 = foo" above is an example of a parameter (also known as an item). Parameters are made up of a key ('var1'), equals sign ('='), and a value ('foo').
47
+ * *Comments*: All the lines starting with a ';' are assumed to be comments, and are ignored.
48
+
49
+ ==== Differences
50
+
51
+ The format of INI files is not well defined. Many programs interpret their
52
+ structure differently than the basic structure that was defined in the above
53
+ example. The following is a basic list of some of the differences:
26
54
 
27
- ; another comment
28
- var1 = baz
29
- var2 = shoodle
55
+ * *Comments*: Programs like Samba accept either ';' or '#' as comments. Comments can be added after parameters with several formats.
56
+ * *Backslashes*: Adding a backslash '\' allows you to continue the value from one line to another. Some formats also allow various escapes with a '\', such as '\n' for newline.
57
+ * <b>Duplicate parameters</b>: Most of the time, you can't have two parameters with the same name in one section. Therefore one can say that parameters are local to the section. Although this behavior can vary between implementations, it is advisable to stick with this rule.
58
+ * <b>Duplicate sections</b>: If you have more than one section with the same name then the last section overrides the previous one. (Some implementations will merge them if they have different keys.)
59
+ * Some implementations allow ':' in place of '='.
30
60
 
31
- === Format
61
+ === This Package
32
62
 
33
- This describes the elements of the INI file format:
63
+ This package supports the standard INI file format described in the *Format*
64
+ section above. The following differences are also supported:
34
65
 
35
- * *Sections*: Section declarations start with '[' and end with ']' as in [section1] and [section2] above. And sections start with section declarations.
36
- * *Parameters*: The "var1 = foo" above is an example of a parameter (also known as an item). Parameters are made up of a key ('var1'), equals sign ('='), and a value ('foo').
37
- * *Comments*: All the lines starting with a ';' are assumed to be comments, and are ignored.
66
+ * *Comments*: The comment character can be specified when an +IniFile+ is created. The comment character must be the first non-whitespace character on a line.
67
+ * *Backslashes*: Backslashes are not supported by this package.
68
+ * <b>Duplicate parameters</b>: Duplicate parameters are allowed in a single section. The last parameter value is the one that will be stored in the +IniFile+.
69
+ * <b>Duplicate sections</b>: Duplicate sections will be merged. Parameters duplicated between to the two sections follow the duplicate parameters rule above.
70
+ * *Parameters*: The parameter separator character can be specified when an +IniFile+ is created.
38
71
 
39
- === Differences
72
+ == INSTALL:
40
73
 
41
- The format of INI files is not well defined. Many programs interpret their
42
- structure differently than the basic structure that was defined in the above
43
- example. The following is a basic list of some of the differences:
74
+ sudo gem install inifile
44
75
 
45
- * *Comments*: Programs like Samba accept either ';' or '#' as comments. Comments can be added after parameters with several formats.
46
- * *Backslashes*: Adding a backslash '\' allows you to continue the value from one line to another. Some formats also allow various escapes with a '\', such as '\n' for newline.
47
- * <b>Duplicate parameters</b>: Most of the time, you can't have two parameters with the same name in one section. Therefore one can say that parameters are local to the section. Although this behavior can vary between implementations, it is advisable to stick with this rule.
48
- * <b>Duplicate sections</b>: If you have more than one section with the same name then the last section overrides the previous one. (Some implementations will merge them if they have different keys.)
49
- * Some implementations allow ':' in place of '='.
76
+ == LICENSE:
50
77
 
51
- == This Package
78
+ MIT License
79
+ Copyright (c) 2006 - 2008
52
80
 
53
- This package supports the standard INI file format described in the *Format*
54
- section above. The following differences are also supported:
81
+ Permission is hereby granted, free of charge, to any person obtaining
82
+ a copy of this software and associated documentation files (the
83
+ 'Software'), to deal in the Software without restriction, including
84
+ without limitation the rights to use, copy, modify, merge, publish,
85
+ distribute, sublicense, and/or sell copies of the Software, and to
86
+ permit persons to whom the Software is furnished to do so, subject to
87
+ the following conditions:
55
88
 
56
- * *Comments*: The comment character can be specified when an +IniFile+ is created. The comment character must be the first non-whitespace character on a line.
57
- * *Backslashes*: Backslashes are not supported by this package.
58
- * <b>Duplicate parameters</b>: Duplicate parameters are allowed in a single section. The last parameter value is the one that will be stored in the +IniFile+.
59
- * <b>Duplicate sections</b>: Duplicate sections will be merged. Parameters duplicated between to the two sections follow the duplicate parameters rule above.
60
- * *Parameters*: The parameter separator character can be specified when an +IniFile+ is created.
89
+ The above copyright notice and this permission notice shall be
90
+ included in all copies or substantial portions of the Software.
61
91
 
92
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
93
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
94
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
95
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
96
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
97
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
98
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,35 @@
1
+ # Look in the tasks/setup.rb file for the various options that can be
2
+ # configured in this Rakefile. The .rake files in the tasks directory
3
+ # are where the options are used.
4
+
5
+ begin
6
+ require 'bones'
7
+ Bones.setup
8
+ rescue LoadError
9
+ begin
10
+ load 'tasks/setup.rb'
11
+ rescue LoadError
12
+ raise RuntimeError, '### please install the "bones" gem ###'
13
+ end
14
+ end
15
+
16
+ ensure_in_path 'lib'
17
+ require 'inifile'
18
+
19
+ task :default => 'test:run'
20
+
21
+ PROJ.name = 'inifile'
22
+ PROJ.summary = 'INI file reader and writer'
23
+ PROJ.authors = 'Tim Pease'
24
+ PROJ.email = 'tim.pease@gmail.com'
25
+ PROJ.url = 'http://codeforpeople.rubyforge.org/inifile'
26
+ PROJ.version = IniFile::VERSION
27
+ PROJ.rubyforge.name = 'codeforpeople'
28
+ PROJ.ignore_file = '.gitignore'
29
+ PROJ.rdoc.remote_dir = 'inifile'
30
+
31
+ PROJ.ann.email[:server] = 'smtp.gmail.com'
32
+ PROJ.ann.email[:port] = 587
33
+ PROJ.ann.email[:from] = 'Tim Pease'
34
+
35
+ # EOF
@@ -1,4 +1,4 @@
1
- # $Id: inifile.rb 57 2006-11-19 20:51:45Z tpease $
1
+ # $Id$
2
2
 
3
3
  #
4
4
  # This class represents the INI file and can be used to parse, modify,
@@ -6,8 +6,12 @@
6
6
  #
7
7
  class IniFile
8
8
 
9
+ # Inifile is enumerable.
10
+ include Enumerable
11
+
9
12
  # :stopdoc:
10
13
  class Error < StandardError; end
14
+ VERSION = '0.2.0'
11
15
  # :startdoc:
12
16
 
13
17
  #
@@ -39,7 +43,7 @@ class IniFile
39
43
  #
40
44
  def initialize( filename, opts = {} )
41
45
  @fn = filename
42
- @comment = opts[:comment] || ';'
46
+ @comment = opts[:comment] || ';#'
43
47
  @param = opts[:parameter] || '='
44
48
  @ini = Hash.new {|h,k| h[k] = Hash.new}
45
49
 
@@ -73,6 +77,32 @@ class IniFile
73
77
  end
74
78
  alias :save :write
75
79
 
80
+ #
81
+ # call-seq:
82
+ # to_s
83
+ #
84
+ # Convert IniFile to text format.
85
+ #
86
+ def to_s
87
+ s = []
88
+ @ini.each do |section,hash|
89
+ s << "[#{section}]"
90
+ hash.each {|param,val| s << "#{param} #{@param} #{val}"}
91
+ s << ""
92
+ end
93
+ s.join("\n")
94
+ end
95
+
96
+ #
97
+ # call-seq:
98
+ # to_h
99
+ #
100
+ # Convert IniFile to hash format.
101
+ #
102
+ def to_h
103
+ @ini.dup
104
+ end
105
+
76
106
  #
77
107
  # call-seq:
78
108
  # each {|section, parameter, value| block}
@@ -221,6 +251,16 @@ class IniFile
221
251
  end
222
252
  alias :== :eql?
223
253
 
254
+ #
255
+ # call-seq:
256
+ # restore
257
+ #
258
+ # Restore data from the ini file. If the state of this object has been
259
+ # changed but not yet saved, this will effectively undo the changes.
260
+ #
261
+ def restore
262
+ parse
263
+ end
224
264
 
225
265
  private
226
266
  #
@@ -0,0 +1,80 @@
1
+
2
+ begin
3
+ require 'bones/smtp_tls'
4
+ rescue LoadError
5
+ require 'net/smtp'
6
+ end
7
+ require 'time'
8
+
9
+ namespace :ann do
10
+
11
+ # A prerequisites task that all other tasks depend upon
12
+ task :prereqs
13
+
14
+ file PROJ.ann.file do
15
+ ann = PROJ.ann
16
+ puts "Generating #{ann.file}"
17
+ File.open(ann.file,'w') do |fd|
18
+ fd.puts("#{PROJ.name} version #{PROJ.version}")
19
+ fd.puts(" by #{Array(PROJ.authors).first}") if PROJ.authors
20
+ fd.puts(" #{PROJ.url}") if PROJ.url.valid?
21
+ fd.puts(" (the \"#{PROJ.release_name}\" release)") if PROJ.release_name
22
+ fd.puts
23
+ fd.puts("== DESCRIPTION")
24
+ fd.puts
25
+ fd.puts(PROJ.description)
26
+ fd.puts
27
+ fd.puts(PROJ.changes.sub(%r/^.*$/, '== CHANGES'))
28
+ fd.puts
29
+ ann.paragraphs.each do |p|
30
+ fd.puts "== #{p.upcase}"
31
+ fd.puts
32
+ fd.puts paragraphs_of(PROJ.readme_file, p).join("\n\n")
33
+ fd.puts
34
+ end
35
+ fd.puts ann.text if ann.text
36
+ end
37
+ end
38
+
39
+ desc "Create an announcement file"
40
+ task :announcement => ['ann:prereqs', PROJ.ann.file]
41
+
42
+ desc "Send an email announcement"
43
+ task :email => ['ann:prereqs', PROJ.ann.file] do
44
+ ann = PROJ.ann
45
+ from = ann.email[:from] || Array(PROJ.authors).first || PROJ.email
46
+ to = Array(ann.email[:to])
47
+
48
+ ### build a mail header for RFC 822
49
+ rfc822msg = "From: #{from}\n"
50
+ rfc822msg << "To: #{to.join(',')}\n"
51
+ rfc822msg << "Subject: [ANN] #{PROJ.name} #{PROJ.version}"
52
+ rfc822msg << " (#{PROJ.release_name})" if PROJ.release_name
53
+ rfc822msg << "\n"
54
+ rfc822msg << "Date: #{Time.new.rfc822}\n"
55
+ rfc822msg << "Message-Id: "
56
+ rfc822msg << "<#{"%.8f" % Time.now.to_f}@#{ann.email[:domain]}>\n\n"
57
+ rfc822msg << File.read(ann.file)
58
+
59
+ params = [:server, :port, :domain, :acct, :passwd, :authtype].map do |key|
60
+ ann.email[key]
61
+ end
62
+
63
+ params[3] = PROJ.email if params[3].nil?
64
+
65
+ if params[4].nil?
66
+ STDOUT.write "Please enter your e-mail password (#{params[3]}): "
67
+ params[4] = STDIN.gets.chomp
68
+ end
69
+
70
+ ### send email
71
+ Net::SMTP.start(*params) {|smtp| smtp.sendmail(rfc822msg, from, to)}
72
+ end
73
+ end # namespace :ann
74
+
75
+ desc 'Alias to ann:announcement'
76
+ task :ann => 'ann:announcement'
77
+
78
+ CLOBBER << PROJ.ann.file
79
+
80
+ # EOF
@@ -0,0 +1,20 @@
1
+
2
+ if HAVE_BONES
3
+
4
+ namespace :bones do
5
+
6
+ desc 'Show the PROJ open struct'
7
+ task :debug do |t|
8
+ atr = if t.application.top_level_tasks.length == 2
9
+ t.application.top_level_tasks.pop
10
+ end
11
+
12
+ if atr then Bones::Debug.show_attr(PROJ, atr)
13
+ else Bones::Debug.show PROJ end
14
+ end
15
+
16
+ end # namespace :bones
17
+
18
+ end # HAVE_BONES
19
+
20
+ # EOF
@@ -0,0 +1,201 @@
1
+
2
+ require 'find'
3
+ require 'rake/packagetask'
4
+ require 'rubygems/user_interaction'
5
+ require 'rubygems/builder'
6
+
7
+ module Bones
8
+ class GemPackageTask < Rake::PackageTask
9
+ # Ruby GEM spec containing the metadata for this package. The
10
+ # name, version and package_files are automatically determined
11
+ # from the GEM spec and don't need to be explicitly provided.
12
+ #
13
+ attr_accessor :gem_spec
14
+
15
+ # Tasks from the Bones gem directory
16
+ attr_reader :bones_files
17
+
18
+ # Create a GEM Package task library. Automatically define the gem
19
+ # if a block is given. If no block is supplied, then +define+
20
+ # needs to be called to define the task.
21
+ #
22
+ def initialize(gem_spec)
23
+ init(gem_spec)
24
+ yield self if block_given?
25
+ define if block_given?
26
+ end
27
+
28
+ # Initialization tasks without the "yield self" or define
29
+ # operations.
30
+ #
31
+ def init(gem)
32
+ super(gem.name, gem.version)
33
+ @gem_spec = gem
34
+ @package_files += gem_spec.files if gem_spec.files
35
+ @bones_files = []
36
+
37
+ local_setup = File.join(Dir.pwd, %w[tasks setup.rb])
38
+ if !test(?e, local_setup)
39
+ Dir.glob(::Bones.path(%w[lib bones tasks *])).each {|fn| bones_files << fn}
40
+ end
41
+ end
42
+
43
+ # Create the Rake tasks and actions specified by this
44
+ # GemPackageTask. (+define+ is automatically called if a block is
45
+ # given to +new+).
46
+ #
47
+ def define
48
+ super
49
+ task :prereqs
50
+ task :package => ['gem:prereqs', "#{package_dir_path}/#{gem_file}"]
51
+ file "#{package_dir_path}/#{gem_file}" => [package_dir_path] + package_files + bones_files do
52
+ when_writing("Creating GEM") {
53
+ chdir(package_dir_path) do
54
+ Gem::Builder.new(gem_spec).build
55
+ verbose(true) {
56
+ mv gem_file, "../#{gem_file}"
57
+ }
58
+ end
59
+ }
60
+ end
61
+
62
+ file package_dir_path => bones_files do
63
+ mkdir_p package_dir rescue nil
64
+
65
+ gem_spec.files = (gem_spec.files +
66
+ bones_files.map {|fn| File.join('tasks', File.basename(fn))}).sort
67
+
68
+ bones_files.each do |fn|
69
+ base_fn = File.join('tasks', File.basename(fn))
70
+ f = File.join(package_dir_path, base_fn)
71
+ fdir = File.dirname(f)
72
+ mkdir_p(fdir) if !File.exist?(fdir)
73
+ if File.directory?(fn)
74
+ mkdir_p(f)
75
+ else
76
+ raise "file name conflict for '#{base_fn}' (conflicts with '#{fn}')" if test(?e, f)
77
+ safe_ln(fn, f)
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ def gem_file
84
+ if @gem_spec.platform == Gem::Platform::RUBY
85
+ "#{package_name}.gem"
86
+ else
87
+ "#{package_name}-#{@gem_spec.platform}.gem"
88
+ end
89
+ end
90
+ end # class GemPackageTask
91
+ end # module Bones
92
+
93
+ namespace :gem do
94
+
95
+ PROJ.gem._spec = Gem::Specification.new do |s|
96
+ s.name = PROJ.name
97
+ s.version = PROJ.version
98
+ s.summary = PROJ.summary
99
+ s.authors = Array(PROJ.authors)
100
+ s.email = PROJ.email
101
+ s.homepage = Array(PROJ.url).first
102
+ s.rubyforge_project = PROJ.rubyforge.name
103
+
104
+ s.description = PROJ.description
105
+
106
+ PROJ.gem.dependencies.each do |dep|
107
+ s.add_dependency(*dep)
108
+ end
109
+
110
+ PROJ.gem.development_dependencies.each do |dep|
111
+ s.add_development_dependency(*dep)
112
+ end
113
+
114
+ s.files = PROJ.gem.files
115
+ s.executables = PROJ.gem.executables.map {|fn| File.basename(fn)}
116
+ s.extensions = PROJ.gem.files.grep %r/extconf\.rb$/
117
+
118
+ s.bindir = 'bin'
119
+ dirs = Dir["{#{PROJ.libs.join(',')}}"]
120
+ s.require_paths = dirs unless dirs.empty?
121
+
122
+ incl = Regexp.new(PROJ.rdoc.include.join('|'))
123
+ excl = PROJ.rdoc.exclude.dup.concat %w[\.rb$ ^(\.\/|\/)?ext]
124
+ excl = Regexp.new(excl.join('|'))
125
+ rdoc_files = PROJ.gem.files.find_all do |fn|
126
+ case fn
127
+ when excl; false
128
+ when incl; true
129
+ else false end
130
+ end
131
+ s.rdoc_options = PROJ.rdoc.opts + ['--main', PROJ.rdoc.main]
132
+ s.extra_rdoc_files = rdoc_files
133
+ s.has_rdoc = true
134
+
135
+ if test ?f, PROJ.test.file
136
+ s.test_file = PROJ.test.file
137
+ else
138
+ s.test_files = PROJ.test.files.to_a
139
+ end
140
+
141
+ # Do any extra stuff the user wants
142
+ PROJ.gem.extras.each do |msg, val|
143
+ case val
144
+ when Proc
145
+ val.call(s.send(msg))
146
+ else
147
+ s.send "#{msg}=", val
148
+ end
149
+ end
150
+ end # Gem::Specification.new
151
+
152
+ Bones::GemPackageTask.new(PROJ.gem._spec) do |pkg|
153
+ pkg.need_tar = PROJ.gem.need_tar
154
+ pkg.need_zip = PROJ.gem.need_zip
155
+ end
156
+
157
+ desc 'Show information about the gem'
158
+ task :debug => 'gem:prereqs' do
159
+ puts PROJ.gem._spec.to_ruby
160
+ end
161
+
162
+ desc 'Write the gemspec '
163
+ task :spec => 'gem:prereqs' do
164
+ File.open("#{PROJ.name}.gemspec", 'w') do |f|
165
+ f.write PROJ.gem._spec.to_ruby
166
+ end
167
+ end
168
+
169
+ desc 'Install the gem'
170
+ task :install => [:clobber, 'gem:package'] do
171
+ sh "#{SUDO} #{GEM} install --local pkg/#{PROJ.gem._spec.full_name}"
172
+
173
+ # use this version of the command for rubygems > 1.0.0
174
+ #sh "#{SUDO} #{GEM} install --no-update-sources pkg/#{PROJ.gem._spec.full_name}"
175
+ end
176
+
177
+ desc 'Uninstall the gem'
178
+ task :uninstall do
179
+ installed_list = Gem.source_index.find_name(PROJ.name)
180
+ if installed_list and installed_list.collect { |s| s.version.to_s}.include?(PROJ.version) then
181
+ sh "#{SUDO} #{GEM} uninstall --version '#{PROJ.version}' --ignore-dependencies --executables #{PROJ.name}"
182
+ end
183
+ end
184
+
185
+ desc 'Reinstall the gem'
186
+ task :reinstall => [:uninstall, :install]
187
+
188
+ desc 'Cleanup the gem'
189
+ task :cleanup do
190
+ sh "#{SUDO} #{GEM} cleanup #{PROJ.gem._spec.name}"
191
+ end
192
+ end # namespace :gem
193
+
194
+
195
+ desc 'Alias to gem:package'
196
+ task :gem => 'gem:package'
197
+
198
+ task :clobber => 'gem:clobber_package'
199
+ remove_desc_for_task 'gem:clobber_package'
200
+
201
+ # EOF