twig 1.0.1 → 1.1

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.
data/lib/twig/display.rb CHANGED
@@ -46,11 +46,22 @@ class Twig
46
46
  new_string
47
47
  end
48
48
 
49
- def branch_list_headers(header_options = { :color => :blue })
49
+ def branch_list_headers(header_options = {})
50
50
  columns_for_date_time = 5
51
51
  columns_per_property = 2
52
52
  branch_indicator_padding = ' ' * CURRENT_BRANCH_INDICATOR.size
53
53
 
54
+ header_options.merge!(
55
+ header_options.inject({}) do |opts, (key, value)|
56
+ if key == :header_color
57
+ opts[:color] = value
58
+ elsif key == :header_weight
59
+ opts[:weight] = value
60
+ end
61
+ opts
62
+ end
63
+ )
64
+
54
65
  out =
55
66
  column(' ', columns_for_date_time) <<
56
67
  Twig::Branch.all_properties.map do |property|
@@ -75,7 +86,7 @@ class Twig
75
86
  is_current_branch = branch.name == current_branch_name
76
87
 
77
88
  properties = Twig::Branch.all_properties.inject({}) do |result, property_name|
78
- property = get_branch_property(branch.name, property_name).strip
89
+ property = (get_branch_property(branch.name, property_name) || '').strip
79
90
  property = column(EMPTY_BRANCH_PROPERTY_INDICATOR) if property.empty?
80
91
  property.gsub!(/[\n\r]+/, ' ')
81
92
  result.merge(property_name => property)
@@ -111,7 +122,11 @@ class Twig
111
122
  string_options << WEIGHTS[options[:weight]] if options[:weight]
112
123
  return string if string_options.empty?
113
124
 
114
- "\033[#{string_options.join(';')}m#{string}\033[0m"
125
+ "\e[#{string_options.join(';')}m#{string}\e[0m"
126
+ end
127
+
128
+ def formatted_string_display_size(string)
129
+ string.gsub(/\e\[[0-9]+(;[0-9]+)?m/, '').size
115
130
  end
116
131
  end # module Display
117
132
  end
data/lib/twig/options.rb CHANGED
@@ -10,7 +10,8 @@ class Twig
10
10
  File.open(config_file_path) do |f|
11
11
  opts = f.read.split("\n").inject({}) do |hsh, opt|
12
12
  key, value = opt.split(':', 2)
13
- hsh.merge(key.strip => value.strip)
13
+ hsh[key.strip] = value.strip if key && value
14
+ hsh
14
15
  end
15
16
 
16
17
  opts.each do |key, value|
@@ -19,6 +20,7 @@ class Twig
19
20
  when 'except-branch' then set_option(:branch_except, value)
20
21
  when 'only-branch' then set_option(:branch_only, value)
21
22
  when 'max-days-old' then set_option(:max_days_old, value)
23
+ when 'header-style' then set_option(:header_style, value)
22
24
  end
23
25
  end
24
26
  end
@@ -36,6 +38,8 @@ class Twig
36
38
  options[:branch_except] = Regexp.new(value)
37
39
  when :branch_only
38
40
  options[:branch_only] = Regexp.new(value)
41
+ when :header_style
42
+ set_header_style_option(value)
39
43
  when :max_days_old
40
44
  if Twig::Util.numeric?(value)
41
45
  options[:max_days_old] = value.to_f
@@ -47,6 +51,27 @@ class Twig
47
51
  end
48
52
  end
49
53
 
54
+ def set_header_style_option(value)
55
+ style_values = value.split(/\s+/).map(&:to_sym)
56
+ colors = Twig::Display::COLORS.keys
57
+ weights = Twig::Display::WEIGHTS.keys
58
+ color = nil
59
+ weight = nil
60
+
61
+ style_values.each do |style_value|
62
+ if !color && colors.include?(style_value)
63
+ color = style_value
64
+ elsif !weight && weights.include?(style_value)
65
+ weight = style_value
66
+ else
67
+ abort %{The value `--header-style=#{value}` is invalid.}
68
+ end
69
+ end
70
+
71
+ options[:header_color] = color if color
72
+ options[:header_weight] = weight if weight
73
+ end
74
+
50
75
  def unset_option(key)
51
76
  options.delete(key)
52
77
  end
data/lib/twig/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Twig
2
- VERSION = '1.0.1'
2
+ VERSION = '1.1'
3
3
  end
@@ -101,17 +101,55 @@ describe Twig::Branch do
101
101
  end
102
102
 
103
103
  describe '#get_property' do
104
+ before :each do
105
+ @branch = Twig::Branch.new('test')
106
+ end
107
+
104
108
  it 'returns a property value' do
105
- branch = Twig::Branch.new('test')
106
109
  property = 'test'
107
110
  value = 'value'
108
111
  Twig.should_receive(:run).
109
- with(%{git config branch.#{branch}.#{property}}).
112
+ with(%{git config branch.#{@branch}.#{property}}).
110
113
  and_return(value)
111
114
 
112
- result = branch.get_property(property)
115
+ result = @branch.get_property(property)
113
116
  result.should == value
114
117
  end
118
+
119
+ it 'removes whitespace from branch property names' do
120
+ bad_property = ' foo foo '
121
+ property = 'foofoo'
122
+ value = 'bar'
123
+ Twig.should_receive(:run).
124
+ with(%{git config branch.#{@branch}.#{property}}).
125
+ and_return(value)
126
+
127
+ result = @branch.get_property(bad_property)
128
+ result.should == value
129
+ end
130
+
131
+ it 'returns nil if the property value is an empty string' do
132
+ property = 'test'
133
+ Twig.should_receive(:run).
134
+ with(%{git config branch.#{@branch}.#{property}}).
135
+ and_return('')
136
+
137
+ result = @branch.get_property(property)
138
+ result.should == nil
139
+ end
140
+
141
+ it 'raises an error if the property name is an empty string' do
142
+ property = ' '
143
+ Twig.should_not_receive(:run)
144
+
145
+ begin
146
+ @branch.get_property(property)
147
+ rescue Twig::Branch::EmptyPropertyNameError => exception
148
+ expected_exception = exception
149
+ end
150
+
151
+ expected_exception.message.should == Twig::Branch::EMPTY_PROPERTY_NAME_ERROR
152
+ end
115
153
  end
116
154
 
117
155
  describe '#set_property' do
@@ -133,33 +171,66 @@ describe Twig::Branch do
133
171
  )
134
172
  end
135
173
 
136
- it 'does nothing if Git cannot set the property value' do
174
+ it 'raises an error if Git cannot set the property value' do
137
175
  property = 'test'
138
176
  value = 'value'
139
177
  Twig.stub(:run) { `(exit 1)`; value } # Set `$?` to `1`
140
178
 
141
- result = @branch.set_property(property, value)
142
- result.should include(
179
+ begin
180
+ @branch.set_property(property, value)
181
+ rescue RuntimeError => exception
182
+ expected_exception = exception
183
+ end
184
+
185
+ expected_exception.message.should include(
143
186
  %{Could not save property "#{property}" as "#{value}" for branch "#{@branch}"}
144
187
  )
145
188
  end
146
189
 
147
- it 'returns an error if trying to set a reserved branch property' do
190
+ it 'raises an error if the property name is an empty string' do
191
+ property = ' '
192
+ value = 'value'
193
+ Twig.should_not_receive(:run)
194
+
195
+ begin
196
+ @branch.set_property(property, value)
197
+ rescue Twig::Branch::EmptyPropertyNameError => exception
198
+ expected_exception = exception
199
+ end
200
+
201
+ expected_exception.message.should == Twig::Branch::EMPTY_PROPERTY_NAME_ERROR
202
+ end
203
+
204
+ it 'raises an error if trying to set a reserved branch property' do
148
205
  property = 'merge'
149
206
  value = 'NOOO'
150
207
  Twig.should_not_receive(:run)
151
208
 
152
- result = @branch.set_property(property, value)
153
- result.should include(%{Can't modify the reserved property "#{property}"})
209
+ begin
210
+ @branch.set_property(property, value)
211
+ rescue ArgumentError => exception
212
+ expected_exception = exception
213
+ end
214
+
215
+ expected_exception.message.should include(
216
+ %{Can't modify the reserved property "#{property}"}
217
+ )
154
218
  end
155
219
 
156
- it 'returns an error if trying to set a branch property to an empty string' do
220
+ it 'raises an error if trying to set a branch property to an empty string' do
157
221
  property = 'test'
158
222
  value = ''
159
223
  Twig.should_not_receive(:run)
160
224
 
161
- result = @branch.set_property(property, value)
162
- result.should include(%{Can't set a branch property to an empty string})
225
+ begin
226
+ @branch.set_property(property, value)
227
+ rescue ArgumentError => exception
228
+ expected_exception = exception
229
+ end
230
+
231
+ expected_exception.message.should include(
232
+ %{Can't set a branch property to an empty string}
233
+ )
163
234
  end
164
235
 
165
236
  it 'removes whitespace from branch property names' do
@@ -225,12 +296,45 @@ describe Twig::Branch do
225
296
  )
226
297
  end
227
298
 
228
- it 'returns an error if the branch does not have the given property' do
229
- property = 'test'
230
- @branch.should_receive(:get_property).with(property).and_return('')
299
+ it 'removes whitespace from branch property names' do
300
+ bad_property = ' foo foo '
301
+ property = 'foofoo'
302
+ @branch.should_receive(:get_property).with(property).and_return('value')
303
+ Twig.should_receive(:run).
304
+ with(%{git config --unset branch.#{@branch}.#{property}})
231
305
 
232
- result = @branch.unset_property(property)
306
+ result = @branch.unset_property(bad_property)
233
307
  result.should include(
308
+ %{Removed property "#{property}" for branch "#{@branch}"}
309
+ )
310
+ end
311
+
312
+ it 'raises an error if the property name is an empty string' do
313
+ bad_property = ' '
314
+ property = ''
315
+ @branch.should_not_receive(:get_property)
316
+ Twig.should_not_receive(:run)
317
+
318
+ begin
319
+ @branch.unset_property(bad_property)
320
+ rescue Twig::Branch::EmptyPropertyNameError => exception
321
+ expected_exception = exception
322
+ end
323
+
324
+ expected_exception.message.should == Twig::Branch::EMPTY_PROPERTY_NAME_ERROR
325
+ end
326
+
327
+ it 'raises an error if the branch does not have the given property' do
328
+ property = 'test'
329
+ @branch.should_receive(:get_property).with(property).and_return(nil)
330
+
331
+ begin
332
+ @branch.unset_property(property)
333
+ rescue Twig::Branch::MissingPropertyError => exception
334
+ expected_exception = exception
335
+ end
336
+
337
+ expected_exception.message.should include(
234
338
  %{The branch "#{@branch}" does not have the property "#{property}"}
235
339
  )
236
340
  end
@@ -39,6 +39,26 @@ describe Twig::Cli do
39
39
  end
40
40
  end
41
41
 
42
+ describe '#help_paragraph' do
43
+ before :each do
44
+ @twig = Twig.new
45
+ end
46
+
47
+ it 'returns long text in a paragraph with line breaks' do
48
+ text = Array.new(5) {
49
+ 'The quick brown fox jumps over the lazy dog.'
50
+ }.join(' ')
51
+
52
+ result = @twig.help_paragraph(text)
53
+
54
+ result.should == [
55
+ "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the",
56
+ "lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps",
57
+ "over the lazy dog. The quick brown fox jumps over the lazy dog."
58
+ ].join("\n")
59
+ end
60
+ end
61
+
42
62
  describe '#read_cli_options!' do
43
63
  before :each do
44
64
  @twig = Twig.new
@@ -105,6 +125,14 @@ describe Twig::Cli do
105
125
  @twig.read_cli_options!(['--version'])
106
126
  end
107
127
 
128
+ it 'recognizes `--header-style`' do
129
+ @twig.options[:header_color].should == Twig::DEFAULT_HEADER_COLOR
130
+ @twig.options[:header_weight].should be_nil
131
+ @twig.read_cli_options!(['--header-style', 'green bold'])
132
+ @twig.options[:header_color].should == :green
133
+ @twig.options[:header_weight].should == :bold
134
+ end
135
+
108
136
  it 'handles invalid options' do
109
137
  @twig.should_receive(:puts) do |message|
110
138
  message.should include('invalid option: --foo')
@@ -201,7 +229,7 @@ describe Twig::Cli do
201
229
 
202
230
  it 'shows an error if getting a property that is not set' do
203
231
  @twig.should_receive(:get_branch_property).
204
- with(@branch_name, @property_name).and_return('')
232
+ with(@branch_name, @property_name).and_return(nil)
205
233
  @twig.should_receive(:abort) do |message|
206
234
  message.should include(
207
235
  %{The branch "#{@branch_name}" does not have the property "#{@property_name}"}
@@ -210,6 +238,18 @@ describe Twig::Cli do
210
238
 
211
239
  @twig.read_cli_args!([@property_name])
212
240
  end
241
+
242
+ it 'shows an error if getting a property whose name is an empty string' do
243
+ property_name = ' '
244
+ error_message = 'test error'
245
+ @twig.should_receive(:get_branch_property).
246
+ with(@branch_name, property_name) do
247
+ raise ArgumentError, error_message
248
+ end
249
+ @twig.should_receive(:abort).with(error_message)
250
+
251
+ @twig.read_cli_args!([property_name])
252
+ end
213
253
  end
214
254
 
215
255
  context 'with a specified branch' do
@@ -228,7 +268,7 @@ describe Twig::Cli do
228
268
 
229
269
  it 'shows an error if getting a property that is not set' do
230
270
  @twig.should_receive(:get_branch_property).
231
- with(@branch_name, @property_name).and_return('')
271
+ with(@branch_name, @property_name).and_return(nil)
232
272
  @twig.should_receive(:abort) do |message|
233
273
  message.should include(
234
274
  %{The branch "#{@branch_name}" does not have the property "#{@property_name}"}
@@ -269,6 +309,30 @@ describe Twig::Cli do
269
309
 
270
310
  @twig.read_cli_args!([@property_name, @property_value])
271
311
  end
312
+
313
+ it 'handles ArgumentError when setting an invalid branch property' do
314
+ error_message = 'test error'
315
+ @twig.should_receive(:current_branch_name).and_return(@branch_name)
316
+ @twig.should_receive(:set_branch_property).
317
+ with(@branch_name, @property_name, '') do
318
+ raise ArgumentError, error_message
319
+ end
320
+ @twig.should_receive(:abort).with(error_message)
321
+
322
+ @twig.read_cli_args!([@property_name, ''])
323
+ end
324
+
325
+ it 'handles RuntimeError when setting an invalid branch property' do
326
+ error_message = 'test error'
327
+ @twig.should_receive(:current_branch_name).and_return(@branch_name)
328
+ @twig.should_receive(:set_branch_property).
329
+ with(@branch_name, @property_name, '') do
330
+ raise RuntimeError, error_message
331
+ end
332
+ @twig.should_receive(:abort).with(error_message)
333
+
334
+ @twig.read_cli_args!([@property_name, ''])
335
+ end
272
336
  end
273
337
 
274
338
  context 'unsetting properties' do
@@ -297,6 +361,30 @@ describe Twig::Cli do
297
361
 
298
362
  @twig.read_cli_args!([])
299
363
  end
364
+
365
+ it 'handles ArgumentError when unsetting an invalid branch property' do
366
+ error_message = 'test error'
367
+ @twig.should_receive(:current_branch_name).and_return(@branch_name)
368
+ @twig.should_receive(:unset_branch_property).
369
+ with(@branch_name, @property_name) do
370
+ raise ArgumentError, error_message
371
+ end
372
+ @twig.should_receive(:abort).with(error_message)
373
+
374
+ @twig.read_cli_args!([])
375
+ end
376
+
377
+ it 'handles MissingPropertyError when unsetting a missing branch property' do
378
+ error_message = 'test error'
379
+ @twig.should_receive(:current_branch_name).and_return(@branch_name)
380
+ @twig.should_receive(:unset_branch_property).
381
+ with(@branch_name, @property_name) do
382
+ raise Twig::Branch::MissingPropertyError, error_message
383
+ end
384
+ @twig.should_receive(:abort).with(error_message)
385
+
386
+ @twig.read_cli_args!([])
387
+ end
300
388
  end
301
389
  end
302
390
 
@@ -36,9 +36,11 @@ describe Twig::Display do
36
36
  end
37
37
 
38
38
  describe '#branch_list_headers' do
39
- it 'returns a string of branch properties and underlines' do
39
+ before :each do
40
40
  Twig::Branch.stub(:all_properties => %w[foo quux])
41
+ end
41
42
 
43
+ it 'returns a string of branch properties and underlines' do
42
44
  result = @twig.branch_list_headers({})
43
45
  result_lines = result.split("\n")
44
46
 
@@ -54,6 +56,36 @@ describe Twig::Display do
54
56
  '---- ' + (' ' * column_width) +
55
57
  ' ------' + (' ' * column_width)
56
58
  end
59
+
60
+ it 'sets a header color' do
61
+ result = @twig.branch_list_headers({ :header_color => :green })
62
+ header_line = result.split("\n").first
63
+ color = Twig::Display::COLORS[:green]
64
+ header_line.gsub(/\s/, '').should ==
65
+ "\e[#{color}mfoo\e[0m" <<
66
+ "\e[#{color}mquux\e[0m" <<
67
+ "\e[#{color}mbranch\e[0m"
68
+ end
69
+
70
+ it 'sets a header weight' do
71
+ result = @twig.branch_list_headers({ :header_weight => :bold })
72
+ header_line = result.split("\n").first
73
+ weight = Twig::Display::WEIGHTS[:bold]
74
+ header_line.gsub(/\s/, '').should ==
75
+ "\e[#{weight}mfoo\e[0m" <<
76
+ "\e[#{weight}mquux\e[0m" <<
77
+ "\e[#{weight}mbranch\e[0m"
78
+ end
79
+
80
+ it 'sets a header color and weight' do
81
+ result = @twig.branch_list_headers({ :header_color => :red, :header_weight => :bold })
82
+ header_line = result.split("\n").first
83
+ color, weight = Twig::Display::COLORS[:red], Twig::Display::WEIGHTS[:bold]
84
+ header_line.gsub(/\s/, '').should ==
85
+ "\e[#{color};#{weight}mfoo\e[0m" <<
86
+ "\e[#{color};#{weight}mquux\e[0m" <<
87
+ "\e[#{color};#{weight}mbranch\e[0m"
88
+ end
57
89
  end
58
90
 
59
91
  describe '#branch_list_line' do
@@ -90,6 +122,19 @@ describe Twig::Display do
90
122
  result.should =~ /2000-01-01\s+foo!\s+bar!\s+#{Regexp.escape(branch.name)}/
91
123
  end
92
124
 
125
+ it 'returns a line containing an empty branch property' do
126
+ Twig::Branch.stub(:all_properties => %w[foo bar baz])
127
+ @twig.should_receive(:get_branch_property).
128
+ with(anything, 'baz').and_return(nil)
129
+ branch = Twig::Branch.new('other-branch')
130
+ branch.should_receive(:last_commit_time).and_return(@commit_time)
131
+
132
+ result = @twig.branch_list_line(branch)
133
+
134
+ empty_indicator = Twig::Display::EMPTY_BRANCH_PROPERTY_INDICATOR
135
+ result.should =~ /2000-01-01\s+foo!\s+bar!\s+#{empty_indicator}\s+#{Regexp.escape(branch.name)}/
136
+ end
137
+
93
138
  it 'changes line break characters to spaces' do
94
139
  branch = Twig::Branch.new('my-branch')
95
140
  branch.should_receive(:last_commit_time).and_return(@commit_time)
@@ -110,12 +155,12 @@ describe Twig::Display do
110
155
 
111
156
  it 'returns a string with a color code' do
112
157
  @twig.format_string('foo', :color => :red).
113
- should == "\033[#{Twig::Display::COLORS[:red]}mfoo\033[0m"
158
+ should == "\e[#{Twig::Display::COLORS[:red]}mfoo\e[0m"
114
159
  end
115
160
 
116
161
  it 'returns a string with a weight code' do
117
162
  @twig.format_string('foo', :weight => :bold).
118
- should == "\033[#{Twig::Display::WEIGHTS[:bold]}mfoo\033[0m"
163
+ should == "\e[#{Twig::Display::WEIGHTS[:bold]}mfoo\e[0m"
119
164
  end
120
165
 
121
166
  it 'returns a string with a color and weight code 'do
@@ -123,7 +168,34 @@ describe Twig::Display do
123
168
  weight_code = Twig::Display::WEIGHTS[:bold]
124
169
 
125
170
  @twig.format_string('foo', :color => :red, :weight => :bold).
126
- should == "\033[#{color_code};#{weight_code}mfoo\033[0m"
171
+ should == "\e[#{color_code};#{weight_code}mfoo\e[0m"
172
+ end
173
+ end
174
+
175
+ describe '#formatted_string_display_size' do
176
+ it 'returns the width of a plain text string' do
177
+ @twig.formatted_string_display_size('foo').should == 3
178
+ end
179
+
180
+ it 'returns the width of a string with color' do
181
+ string = @twig.format_string('foo', :color => :red)
182
+ string.size.should > 3 # Precondition
183
+
184
+ @twig.formatted_string_display_size(string).should == 3
185
+ end
186
+
187
+ it 'returns the width of a string with weight' do
188
+ string = @twig.format_string('foo', :weight => :bold)
189
+ string.size.should > 3 # Precondition
190
+
191
+ @twig.formatted_string_display_size(string).should == 3
192
+ end
193
+
194
+ it 'returns the width of a string with color and weight' do
195
+ string = @twig.format_string('foo', :color => :red, :weight => :bold)
196
+ string.size.should > 3 # Precondition
197
+
198
+ @twig.formatted_string_display_size(string).should == 3
127
199
  end
128
200
  end
129
201
  end