loquacious 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,75 @@
1
+
2
+ class String
3
+
4
+ # call-seq:
5
+ # reduce( width, ellipses = '...' ) #=> string
6
+ #
7
+ # Reduce the size of the current string to the given _width_ by removing
8
+ # characters from the middle of the string and replacing them with
9
+ # _ellipses_. If the _width_ is greater than the length of the string, the
10
+ # string is returned unchanged. If the _width_ is less than the length of
11
+ # the _ellipses_, then the _ellipses_ are returned.
12
+ #
13
+ def reduce( width, ellipses = '...')
14
+ raise ArgumentError, "width cannot be negative: #{width}" if width < 0
15
+
16
+ return self if length <= width
17
+
18
+ remove = length - width + ellipses.length
19
+ return ellipses.dup if remove >= length
20
+
21
+ left_end = (length + 1 - remove) / 2
22
+ right_start = left_end + remove
23
+
24
+ left = self[0,left_end]
25
+ right = self[right_start,length-right_start]
26
+
27
+ left << ellipses << right
28
+ end
29
+
30
+ # call-seq:
31
+ # "foo".indent( 2 ) #=> " foo"
32
+ # "foo".indent( '# ' ) #=> "# foo"
33
+ #
34
+ # Indent the string by the given number of spaces. Alternately, if a
35
+ # leader string is given it will be used to indent with instead of spaces.
36
+ # Indentation is performed at the beginning of the string and after every
37
+ # newline character.
38
+ #
39
+ # "foo\nbar".indent( 2 ) #=> " foo\n bar"
40
+ #
41
+ def indent( leader )
42
+ leader =
43
+ Numeric === leader ? ' ' * leader.to_i : leader.to_s
44
+ str = self.gsub("\n", "\n"+leader)
45
+ str.insert(0, leader)
46
+ str
47
+ end
48
+
49
+ # call-seq:
50
+ # " | foo\n | bar".gutter! #=> " foo\n bar"
51
+ #
52
+ # Removes a leading _gutter_ from all lines in the string. The gutter is
53
+ # defined leading whitespace followed by a single pipe character. This
54
+ # method is very useful with heredocs.
55
+ #
56
+ # The string will be altered by this method.
57
+ #
58
+ def gutter!
59
+ gsub! %r/^[\t\f\r ]*\|?/, ''
60
+ self
61
+ end
62
+
63
+ # call-seq:
64
+ # " | foo\n | bar".gutter! #=> " foo\n bar"
65
+ #
66
+ # Removes a leading _gutter_ from all lines in the string. The gutter is
67
+ # defined leading whitespace followed by a single pipe character. This
68
+ # method is very useful with heredocs.
69
+ #
70
+ def gutter
71
+ self.dup.gutter!
72
+ end
73
+ end # class String
74
+
75
+ # EOF
@@ -0,0 +1,37 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{loquacious}
5
+ s.version = "1.0.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Tim Pease"]
9
+ s.date = %q{2009-04-04}
10
+ s.description = %q{Descriptive configuration files for Ruby written in Ruby. Loquacious provides a very open configuration system written in ruby and descriptions for each configuration attribute. The attributes and descriptions can be iterated over allowing for helpful information about those attributes to be displayed to the user. In the simple case we have a file something like Loquacious.configuration_for('app') { name 'value', :desc => "Defines the name" foo 'bar', :desc => "FooBar" id 42, :desc => "Ara T. Howard" } Which can be loaded via the standard Ruby loading mechanisms Kernel.load 'config/app.rb' The attributes and their descriptions can be printed by using a Help object help = Loquacious.help_for('app') help.show :values => true # show the values for the attributes, too Descriptions are optional, and configurations can be nested arbitrarily deep. Loquacious.configuration_for('nested') { desc "The outermost level" a { desc "One more level in" b { desc "Finally, a real value" c 'value' } } } config = Loquacious.configuration_for('nested') p config.a.b.c #=> "value" And as you can see, descriptions can either be given inline after the value or they can appear above the attribute and value on their own line.}
11
+ s.email = %q{tim.pease@gmail.com}
12
+ s.extra_rdoc_files = ["History.txt", "README.rdoc"]
13
+ s.files = ["History.txt", "README.rdoc", "Rakefile", "examples/gutters.rb", "examples/nested.rb", "examples/simple.rb", "lib/loquacious.rb", "lib/loquacious/configuration.rb", "lib/loquacious/configuration/help.rb", "lib/loquacious/configuration/iterator.rb", "lib/loquacious/core_ext/string.rb", "loquacious.gemspec", "spec/configuration_spec.rb", "spec/help_spec.rb", "spec/iterator_spec.rb", "spec/loquacious_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "spec/string_spec.rb"]
14
+ s.has_rdoc = true
15
+ s.homepage = %q{http://codeforpeople.rubyforge.org/loquacious}
16
+ s.rdoc_options = ["--main", "README.rdoc"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = %q{codeforpeople}
19
+ s.rubygems_version = %q{1.3.1}
20
+ s.summary = %q{Descriptive configuration files for Ruby written in Ruby}
21
+
22
+ if s.respond_to? :specification_version then
23
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
24
+ s.specification_version = 2
25
+
26
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
27
+ s.add_runtime_dependency(%q<rspec>, [">= 1.1.12"])
28
+ s.add_development_dependency(%q<bones>, [">= 2.4.2"])
29
+ else
30
+ s.add_dependency(%q<rspec>, [">= 1.1.12"])
31
+ s.add_dependency(%q<bones>, [">= 2.4.2"])
32
+ end
33
+ else
34
+ s.add_dependency(%q<rspec>, [">= 1.1.12"])
35
+ s.add_dependency(%q<bones>, [">= 2.4.2"])
36
+ end
37
+ end
@@ -0,0 +1,152 @@
1
+
2
+ require File.join(File.dirname(__FILE__), %w[spec_helper])
3
+
4
+ describe Loquacious::Configuration do
5
+ before(:all) do
6
+ @respond_to = Object.instance_method(:respond_to?)
7
+ end
8
+
9
+ before(:each) do
10
+ @obj = Loquacious::Configuration.new
11
+ end
12
+
13
+ it 'should initialize from a block' do
14
+ obj = Loquacious::Configuration.new {
15
+ first 'foo'
16
+ second 'bar'
17
+ }
18
+ obj.first.should == 'foo'
19
+ obj.second.should == 'bar'
20
+ obj.third.should be_nil
21
+ end
22
+
23
+ it 'should respond to any method' do
24
+ @obj.first.should be_nil
25
+ @obj.first = 'foo'
26
+ @obj.first.should == 'foo'
27
+
28
+ @obj.second = 'bar'
29
+ @obj.second.should == 'bar'
30
+ end
31
+
32
+ it 'should deine attribute accessors when first used' do
33
+ m = @respond_to.bind(@obj)
34
+ m.call(:foo).should == false
35
+ m.call(:foo=).should == false
36
+
37
+ @obj.foo
38
+ m.call(:foo).should == true
39
+ m.call(:foo=).should == true
40
+ end
41
+
42
+ it 'should provide a hash object for storing method descriptions' do
43
+ h = @obj.__desc
44
+ @obj.__desc.should equal(h)
45
+ end
46
+
47
+ # -----------------------------------------------------------------------
48
+ describe 'when merging' do
49
+
50
+ it 'should merge the contents of another Configuration' do
51
+ other = Loquacious::Configuration.new {
52
+ first 'foo', :desc => 'foo method'
53
+ second 'bar', :desc => 'bar method'
54
+ }
55
+
56
+ @obj.first.should be_nil
57
+ @obj.second.should be_nil
58
+ @obj.__desc.should == {}
59
+
60
+ @obj.merge! other
61
+ @obj.first.should == 'foo'
62
+ @obj.second.should == 'bar'
63
+ @obj.__desc.should == {
64
+ :first => 'foo method',
65
+ :second => 'bar method'
66
+ }
67
+ end
68
+
69
+ it 'should recursively merge nested Configuration' do
70
+ other = Loquacious::Configuration.new {
71
+ first 'foo', :desc => 'foo method'
72
+ second 'bar', :desc => 'bar method'
73
+
74
+ desc 'the third group'
75
+ third {
76
+ answer 42, :desc => 'life the universe and everything'
77
+ }
78
+ }
79
+
80
+ @obj = Loquacious::Configuration.new {
81
+ third {
82
+ question '?', :desc => 'perhaps you do not understand'
83
+ }
84
+ }
85
+
86
+ @obj.merge! other
87
+
88
+ @obj.first.should == 'foo'
89
+ @obj.second.should == 'bar'
90
+ @obj.third.question.should == '?'
91
+ @obj.third.answer.should == 42
92
+
93
+ @obj.__desc.should == {
94
+ :first => 'foo method',
95
+ :second => 'bar method',
96
+ :third => 'the third group'
97
+ }
98
+ @obj.third.__desc.should == {
99
+ :question => 'perhaps you do not understand',
100
+ :answer => 'life the universe and everything'
101
+ }
102
+ end
103
+
104
+ it 'should raise an error when merging with an unknown object' do
105
+ lambda {@obj.merge! 'foo'}.
106
+ should raise_error(Loquacious::Configuration::Error, "can only merge another Configuration")
107
+ end
108
+ end
109
+
110
+ # -----------------------------------------------------------------------
111
+ describe 'when working with descriptions' do
112
+
113
+ it 'should consume leading whitespace' do
114
+ other = Loquacious::Configuration.new {
115
+ desc <<-STR
116
+ This is the first thing we are defining in this config.
117
+ It has a multiline comment.
118
+ STR
119
+ first 'foo'
120
+ second 'bar', :desc => "bar method\n also a multiline comment"
121
+ }
122
+
123
+ other.__desc[:first].should == "This is the first thing we are defining in this config.\nIt has a multiline comment."
124
+ other.__desc[:second].should == "bar method\nalso a multiline comment"
125
+ end
126
+
127
+ it 'should leave whitespace after a gutter marker' do
128
+ other = Loquacious::Configuration.new {
129
+ desc <<-STR
130
+ | This is the first thing we are defining in this config.
131
+ | It has a multiline comment.
132
+ STR
133
+ first 'foo'
134
+
135
+ desc <<-DESC
136
+ This is a short explanation
137
+
138
+ Example:
139
+ | do this then that
140
+ | followed by this line
141
+ DESC
142
+ second 'bar'
143
+ }
144
+
145
+ other.__desc[:first].should == " This is the first thing we are defining in this config.\n It has a multiline comment."
146
+ other.__desc[:second].should == "This is a short explanation\n\nExample:\n do this then that\n followed by this line"
147
+ end
148
+
149
+ end
150
+ end
151
+
152
+ # EOF
data/spec/help_spec.rb ADDED
@@ -0,0 +1,323 @@
1
+
2
+ require File.join(File.dirname(__FILE__), %w[spec_helper])
3
+
4
+ describe Loquacious::Configuration::Help do
5
+
6
+ before :all do
7
+ @sio = StringIO.new
8
+ end
9
+
10
+ before :each do
11
+ @config = Loquacious.configuration_for 'specs'
12
+ @help = Loquacious::Configuration::Help.new 'specs', :io => @sio
13
+ @sio.clear
14
+ end
15
+
16
+ it "returns a help object by name" do
17
+ help = Loquacious::Configuration::Help.new 'specs'
18
+ config = help.instance_variable_get(:@config)
19
+ config.should equal(@config)
20
+ end
21
+
22
+ it "returns a help object for a configuration" do
23
+ help = Loquacious::Configuration::Help.new @config
24
+ config = help.instance_variable_get(:@config)
25
+ config.should equal(@config)
26
+ end
27
+
28
+ it "raises an error for invalid attribute names" do
29
+ lambda {@help.show(42)}.should raise_error(
30
+ Loquacious::Configuration::Help::Error,
31
+ "cannot convert 42 into an attribute identifier"
32
+ )
33
+ end
34
+
35
+ it "prints out all attribues" do
36
+ str = <<-OUTPUT
37
+ | foo method
38
+ | - first
39
+ |
40
+ | bar method
41
+ | - second
42
+ |
43
+ | the third group
44
+ | - third
45
+ |
46
+ | life the universe and everything
47
+ | - third.answer
48
+ |
49
+ | perhaps you do not understand
50
+ | - third.question
51
+ |
52
+ OUTPUT
53
+
54
+ @help.show_all
55
+ @sio.to_s.should == str.gutter!
56
+ end
57
+
58
+ it "prints out a specific attribute" do
59
+ str = <<-OUTPUT
60
+ | bar method
61
+ | - second
62
+ |
63
+ OUTPUT
64
+ @help.show_attribute :second
65
+ @sio.to_s.should == str.gutter!
66
+ end
67
+
68
+ it "properly parses nested attributes" do
69
+ str = <<-OUTPUT
70
+ | the third group
71
+ | - third
72
+ |
73
+ | life the universe and everything
74
+ | - third.answer
75
+ |
76
+ | perhaps you do not understand
77
+ | - third.question
78
+ |
79
+ OUTPUT
80
+ @help.show_attribute 'third'
81
+ @sio.to_s.should == str.gutter!
82
+
83
+ @sio.clear
84
+ str = <<-OUTPUT
85
+ | perhaps you do not understand
86
+ | - third.question
87
+ |
88
+ OUTPUT
89
+ @help.show_attribute %w[third question]
90
+ @sio.to_s.should == str.gutter!
91
+
92
+ @sio.clear
93
+ str = <<-OUTPUT
94
+ | life the universe and everything
95
+ | - third.answer
96
+ |
97
+ OUTPUT
98
+ @help.show_attribute 'third.answer'
99
+ @sio.to_s.should == str.gutter!
100
+ end
101
+
102
+ it "preserves indentation for descriptions" do
103
+ Loquacious.configuration_for('specs') do
104
+ desc <<-DESC
105
+ This is a multiline description that has an example.
106
+ |
107
+ | foo = %w[one two three]
108
+ |
109
+ See, the example is right above this line.
110
+ Hope it was instructive.
111
+ DESC
112
+ fourth 'the fourth value'
113
+ end
114
+
115
+ str = <<-OUTPUT
116
+ | This is a multiline description that has an example.
117
+ |
118
+ | foo = %w[one two three]
119
+ |
120
+ | See, the example is right above this line.
121
+ | Hope it was instructive.
122
+ | - fourth
123
+ |
124
+ OUTPUT
125
+ @help.show_attribute 'fourth'
126
+ @sio.to_s.should == str.gutter!
127
+ end
128
+
129
+ it "pretty prints values" do
130
+ str = <<-OUTPUT
131
+ | foo method
132
+ | - first => "foo"
133
+ |
134
+ | bar method
135
+ | - second => "bar"
136
+ |
137
+ | the third group
138
+ | - third
139
+ |
140
+ | life the universe and everything
141
+ | - third.answer => 42
142
+ |
143
+ | perhaps you do not understand
144
+ | - third.question => :symbol
145
+ |
146
+ OUTPUT
147
+ @help.show :values => true
148
+ @sio.to_s.should == str.gutter!
149
+ end
150
+
151
+ it "closely packs attributes when descriptions are omitted" do
152
+ str = <<-OUTPUT
153
+ | - first => "foo"
154
+ | - second => "bar"
155
+ | - third
156
+ | - third.answer => 42
157
+ | - third.question => :symbol
158
+ OUTPUT
159
+ @help.show_all :values => true, :descriptions => false
160
+ @sio.to_s.should == str.gutter!
161
+ end
162
+
163
+ it "automatically picks up changes to the configuration" do
164
+ Loquacious.configuration_for('specs') do
165
+ fifth 'foo', :desc => 'the fifth configuration setting'
166
+ end
167
+
168
+ str = <<-OUTPUT
169
+ | the fifth configuration setting
170
+ | - fifth
171
+ |
172
+ OUTPUT
173
+ @help.show_attribute 'fifth'
174
+ @sio.to_s.should == str.gutter!
175
+ end
176
+
177
+ it "uses a custom name leader" do
178
+ help = Loquacious.help_for 'specs', :io => @sio, :name_leader => ' ## '
179
+ str = <<-OUTPUT
180
+ | foo method
181
+ | ## first
182
+ |
183
+ | bar method
184
+ | ## second
185
+ |
186
+ | the third group
187
+ | ## third
188
+ |
189
+ | life the universe and everything
190
+ | ## third.answer
191
+ |
192
+ | perhaps you do not understand
193
+ | ## third.question
194
+ |
195
+ OUTPUT
196
+ help.show_all
197
+ @sio.to_s.should == str.gutter!
198
+
199
+ @sio.clear
200
+ str = <<-OUTPUT
201
+ | ## first => "foo"
202
+ | ## second => "bar"
203
+ | ## third
204
+ | ## third.answer => 42
205
+ | ## third.question => :symbol
206
+ OUTPUT
207
+ help.show_all :values => true, :descriptions => false
208
+ @sio.to_s.should == str.gutter!
209
+ end
210
+
211
+ it "uses a custom name length" do
212
+ help = Loquacious.help_for 'specs', :io => @sio, :name_length => 10
213
+ str = <<-OUTPUT
214
+ | foo method
215
+ | - first
216
+ |
217
+ | bar method
218
+ | - second
219
+ |
220
+ | the third group
221
+ | - third
222
+ |
223
+ | life the universe and everything
224
+ | - thir...wer
225
+ |
226
+ | perhaps you do not understand
227
+ | - thir...ion
228
+ |
229
+ OUTPUT
230
+ help.show_all
231
+ @sio.to_s.should == str.gutter!
232
+
233
+ @sio.clear
234
+ str = <<-OUTPUT
235
+ | - first => "foo"
236
+ | - second => "bar"
237
+ | - third
238
+ | - thir...wer => 42
239
+ | - thir...ion => :symbol
240
+ OUTPUT
241
+ help.show_all :values => true, :descriptions => false
242
+ @sio.to_s.should == str.gutter!
243
+ end
244
+
245
+ it "uses a custom name/value separator" do
246
+ help = Loquacious.help_for 'specs', :io => @sio, :name_value_sep => ' :: '
247
+ str = <<-OUTPUT
248
+ | foo method
249
+ | - first :: "foo"
250
+ |
251
+ | bar method
252
+ | - second :: "bar"
253
+ |
254
+ | the third group
255
+ | - third
256
+ |
257
+ | life the universe and everything
258
+ | - third.answer :: 42
259
+ |
260
+ | perhaps you do not understand
261
+ | - third.question :: :symbol
262
+ |
263
+ OUTPUT
264
+ help.show_all :values => true
265
+ @sio.to_s.should == str.gutter!
266
+
267
+ @sio.clear
268
+ str = <<-OUTPUT
269
+ | - first :: "foo"
270
+ | - second :: "bar"
271
+ | - third
272
+ | - third.answer :: 42
273
+ | - third.question :: :symbol
274
+ OUTPUT
275
+ help.show_all :values => true, :descriptions => false
276
+ @sio.to_s.should == str.gutter!
277
+ end
278
+
279
+ it "uses a custom description leader" do
280
+ Loquacious.configuration_for('specs') do
281
+ desc <<-DESC
282
+ This is a multiline description that has an example.
283
+ |
284
+ | foo = %w[one two three]
285
+ |
286
+ See, the example is right above this line.
287
+ Hope it was instructive.
288
+ DESC
289
+ fourth 'the fourth value'
290
+ end
291
+
292
+ help = Loquacious.help_for 'specs', :io => @sio, :desc_leader => '~'
293
+ str = <<-OUTPUT
294
+ |~foo method
295
+ | - first => "foo"
296
+ |
297
+ |~This is a multiline description that has an example.
298
+ |~
299
+ |~ foo = %w[one two three]
300
+ |~
301
+ |~See, the example is right above this line.
302
+ |~Hope it was instructive.
303
+ | - fourth => "the fourth value"
304
+ |
305
+ |~bar method
306
+ | - second => "bar"
307
+ |
308
+ |~the third group
309
+ | - third
310
+ |
311
+ |~life the universe and everything
312
+ | - third.answer => 42
313
+ |
314
+ |~perhaps you do not understand
315
+ | - third.question => :symbol
316
+ |
317
+ OUTPUT
318
+ help.show_all :values => true
319
+ @sio.to_s.should == str.gutter!
320
+ end
321
+ end
322
+
323
+ # EOF