configit 0.1.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,5 @@
1
+ module Configit
2
+ class ConfigitException < Exception; end
3
+ class AttributeAlreadyDefined < ConfigitException; end
4
+ class ArgumentError < ::ArgumentError; end
5
+ end
@@ -0,0 +1,222 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. spec_helper])
2
+
3
+ require 'tempfile'
4
+
5
+ describe Configit::Base do
6
+ before :each do
7
+ Object.send(:remove_const, :FooConfig) if Object.const_defined? :FooConfig
8
+ class FooConfig < Configit::Base; end
9
+ end
10
+
11
+ describe "class.attribute" do
12
+ before do
13
+ @foo = FooConfig.attribute :foo, "Foo description",
14
+ :required => true,
15
+ :type => :integer
16
+ @bar = FooConfig.attribute :bar
17
+ end
18
+
19
+ it "should add the attribute to the schema of the class" do
20
+ FooConfig.schema[:foo].should == @foo
21
+ end
22
+
23
+ it "should define the attribute successfully" do
24
+ @foo.should_not be_nil
25
+ @foo.should be_a Configit::AttributeDefinition
26
+ end
27
+
28
+ it "should set the name of the attribute" do
29
+ @foo.name.should == :foo
30
+ end
31
+
32
+ it "should set the desc of the attribute" do
33
+ @foo.desc.should == "Foo description"
34
+ end
35
+
36
+ it "should set the required state of the attribute" do
37
+ @foo.required?.should == true
38
+ end
39
+
40
+ it "should set the type of the attribute" do
41
+ @foo.type.should == :integer
42
+ end
43
+
44
+ it "should add an attribute accessor to the class for the attribute" do
45
+ config = FooConfig.new
46
+ config.respond_to?(:foo).should be_true
47
+ config.respond_to?(:foo=).should be_true
48
+ end
49
+
50
+ it "should properly convert the type of attribute on read and set" do
51
+ FooConfig.attribute :integer, :type => :integer
52
+ FooConfig.attribute :string, :type => :string
53
+ FooConfig.attribute :symbol, :type => :symbol
54
+ FooConfig.attribute :float, :type => :float
55
+
56
+ config = FooConfig.new
57
+
58
+ config.integer = "3"
59
+ config.attributes[:integer].should == "3"
60
+ config.integer.should == 3
61
+ config.integer = 3
62
+ config.integer.should == 3
63
+ config.integer = 3.3
64
+ config.integer.should == 3
65
+ config.integer = "foo"
66
+ config.integer.should == 0
67
+
68
+ # Need to test rest of conversions
69
+ pending
70
+ end
71
+
72
+ it "should set type to :string by default" do
73
+ @bar.type.should == :string
74
+ end
75
+
76
+ it "should set required to false by default" do
77
+ @bar.required?.should == false
78
+ end
79
+
80
+ it "should raise an AttributeAlreadyDefined exception when an attribute is
81
+ defined twice" do
82
+ lambda {
83
+ FooConfig.attribute :foo
84
+ }.should raise_error(Configit::AttributeAlreadyDefined)
85
+ end
86
+ end
87
+
88
+ it "should enforce that required attributes are present" do
89
+ FooConfig.attribute :foo, :required => true
90
+ config = FooConfig.load_from_string("")
91
+ config.valid?.should be_false
92
+ end
93
+
94
+ it "should be valid when non required attributes are abset" do
95
+ FooConfig.attribute :foo, :required => false
96
+ config = FooConfig.load_from_string("")
97
+ config.valid?.should be_true
98
+ end
99
+
100
+ describe ".load_from_string!" do
101
+ it "should raise an ArgumentError if the config is not valid" do
102
+ lambda {
103
+ FooConfig.load_from_string! "asdfasdf: adf"
104
+ }.should raise_error(ArgumentError, /asdfasdf/)
105
+ end
106
+ end
107
+
108
+ describe ".load_from_file!" do
109
+ it "should raise an ArgumentError if the config is not valid" do
110
+ file = Tempfile.new("config")
111
+ file.write "foo1: bar"
112
+ file.flush
113
+ file.close
114
+ lambda {
115
+ config = FooConfig.load_from_file!(file.path)
116
+ }.should raise_error(ArgumentError, /foo1/)
117
+ end
118
+ end
119
+
120
+ describe ".load_from_string" do
121
+ before do
122
+ FooConfig.attribute :foo, :type => :integer
123
+ FooConfig.attribute :bar, :type => :string
124
+ end
125
+
126
+ it "should load a valid yaml config from a string successfully" do
127
+ config = FooConfig.load_from_string %q{
128
+ foo: 3
129
+ bar: bar value
130
+ }
131
+
132
+ config.foo.should == 3
133
+ config.bar.should == "bar value"
134
+ config.valid?.should be_true
135
+ end
136
+
137
+ it "should create errors when it sees unknown schema" do
138
+ config = FooConfig.load_from_string %q{
139
+ something: 3
140
+ bar: bar value
141
+ }
142
+
143
+ config.valid?.should == false
144
+ config.errors.first.should =~ /something/
145
+ end
146
+
147
+ it "should evaluate erb successfully" do
148
+ config = FooConfig.load_from_string %q{
149
+ bar: <%= "foo " + "bar" %>
150
+ }
151
+ config.bar.should == "foo bar"
152
+ end
153
+
154
+ it "should not evaluate erb if .evaluate_erb is set to false" do
155
+ FooConfig.evaluate_erb = false
156
+ config = FooConfig.load_from_string %q{
157
+ bar: <%= 3 %>
158
+ }
159
+ config.bar.should == "<%= 3 %>"
160
+ end
161
+ end
162
+
163
+ describe ".load_from_file" do
164
+ before do
165
+ FooConfig.attribute :foo
166
+ FooConfig.attribute :bar
167
+ end
168
+
169
+ it "should load from a file successfully" do
170
+ file = Tempfile.new("config")
171
+ file.write "foo: bar"
172
+ file.flush
173
+ file.close
174
+ config = FooConfig.load_from_file(file.path)
175
+ config.foo.should == 'bar'
176
+ end
177
+
178
+ it "should raise an ArgumentError when the file does not exist" do
179
+ lambda {
180
+ FooConfig.load_from_file("/etc/kajdf33sdf")
181
+ }.should raise_error(ArgumentError)
182
+ end
183
+
184
+ it "should raise an ArgumentError if the file is not readable" do
185
+ file = Tempfile.new("config")
186
+ file.write "foo: bar"
187
+ file.flush
188
+ file.close
189
+ File.chmod(0000, file.path)
190
+ lambda {
191
+ config = FooConfig.load_from_file(file.path)
192
+ }.should raise_error(ArgumentError)
193
+ end
194
+ end
195
+
196
+ describe ".clear_errors" do
197
+ it "should clear the errors on the config" do
198
+ config = FooConfig.new
199
+ config.attributes['foo'] = 3
200
+ config.valid?.should == false
201
+ config.clear_errors
202
+ config.errors.should == []
203
+ end
204
+ end
205
+
206
+ it "should enable you to override attribute methods and use super" do
207
+ FooConfig.attribute :foo, :type => :symbol
208
+ FooConfig.attribute :bar, :type => :symbol
209
+ FooConfig.class_eval do
210
+ def foo
211
+ super || bar
212
+ end
213
+ end
214
+ config = FooConfig.new
215
+ config.bar = :bar
216
+ config.foo.should == :bar
217
+ config.foo = :foo
218
+ config.foo.should == :foo
219
+ end
220
+ end
221
+
222
+ # EOF
@@ -0,0 +1,7 @@
1
+
2
+ require File.join(File.dirname(__FILE__), %w[spec_helper])
3
+
4
+ describe Configit do
5
+ end
6
+
7
+ # EOF
data/spec/spec.opts ADDED
@@ -0,0 +1,7 @@
1
+ --colour
2
+ --format
3
+ progress
4
+ --loadby
5
+ mtime
6
+ --reverse
7
+
@@ -0,0 +1,16 @@
1
+
2
+ require File.expand_path(
3
+ File.join(File.dirname(__FILE__), %w[.. lib configit]))
4
+
5
+ Spec::Runner.configure do |config|
6
+ # == Mock Framework
7
+ #
8
+ # RSpec uses it's own mocking framework by default. If you prefer to
9
+ # use mocha, flexmock or RR, uncomment the appropriate line:
10
+ #
11
+ # config.mock_with :mocha
12
+ # config.mock_with :flexmock
13
+ # config.mock_with :rr
14
+ end
15
+
16
+ # EOF
data/tasks/ann.rake ADDED
@@ -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
data/tasks/bones.rake ADDED
@@ -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
data/tasks/gem.rake ADDED
@@ -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