twig 1.2.1 → 1.3

Sign up to get free protection for your applications and to get access to all the features.
data/lib/twig/github.rb CHANGED
@@ -1,12 +1,11 @@
1
1
  class Twig
2
2
  class GithubRepo
3
- def self.run(command)
4
- # Duplicated from `Twig.run` for making lightweight subcommands.
5
- `#{command}`.strip
6
- end
7
-
8
3
  def initialize
9
- if origin_url.empty? || username.empty? || repository.empty?
4
+ unless Twig.repo?
5
+ abort 'Current directory is not a git repository.'
6
+ end
7
+
8
+ if origin_url.empty? || !github_repo? || username.empty? || repository.empty?
10
9
  abort_for_non_github_repo
11
10
  end
12
11
 
@@ -14,13 +13,17 @@ class Twig
14
13
  end
15
14
 
16
15
  def origin_url
17
- @origin_url ||= Twig::GithubRepo.run('git config remote.origin.url')
16
+ @origin_url ||= Twig.run('git config remote.origin.url')
18
17
  end
19
18
 
20
19
  def origin_url_parts
21
20
  @origin_url_parts ||= origin_url.split(/[\/:]/)
22
21
  end
23
22
 
23
+ def github_repo?
24
+ origin_url.include?('github.com')
25
+ end
26
+
24
27
  def username
25
28
  @username ||= origin_url_parts[-2] || ''
26
29
  end
data/lib/twig/options.rb CHANGED
@@ -2,29 +2,48 @@ class Twig
2
2
  module Options
3
3
 
4
4
  CONFIG_FILE = '~/.twigrc'
5
+ MIN_PROPERTY_WIDTH = 3
5
6
 
6
7
  def read_config_file!
7
8
  config_file_path = File.expand_path(Twig::CONFIG_FILE)
8
9
  return unless File.readable?(config_file_path)
9
10
 
10
11
  File.open(config_file_path) do |f|
11
- opts = f.read.split("\n").inject({}) do |hsh, opt|
12
- key, value = opt.split(':', 2)
13
- hsh[key.strip] = value.strip if key && value
12
+ opts = f.read.split("\n").inject({}) do |hsh, line|
13
+ line = line.strip
14
+
15
+ if line !~ /^#/
16
+ key, value = line.split(':', 2)
17
+ hsh[key.strip] = value.strip if key && value
18
+ end
19
+
14
20
  hsh
15
21
  end
16
22
 
17
23
  opts.each do |key, value|
18
24
  case key
19
- when 'branch' then set_option(:branch, value)
20
- when 'header-style' then set_option(:header_style, value)
21
- when 'max-days-old' then set_option(:max_days_old, value)
25
+
26
+ # Filtering branches:
27
+ when 'branch'
28
+ set_option(:branch, value)
29
+ when 'max-days-old'
30
+ set_option(:max_days_old, value)
22
31
  when /^except-/
23
32
  property_name = key.sub(/^except-/, '').to_sym
24
33
  set_option(:property_except, property_name => value)
25
34
  when /^only-/
26
35
  property_name = key.sub(/^only-/, '').to_sym
27
36
  set_option(:property_only, property_name => value)
37
+
38
+ # Displaying branches:
39
+ when 'header-style'
40
+ set_option(:header_style, value)
41
+ when 'reverse'
42
+ set_option(:reverse, value)
43
+ when /-width$/
44
+ property_name = key.sub(/-width$/, '').to_sym
45
+ set_option(:property_width, property_name => value)
46
+
28
47
  end
29
48
  end
30
49
  end
@@ -33,7 +52,7 @@ class Twig
33
52
  def set_option(key, value)
34
53
  case key
35
54
  when :branch
36
- if branch_names.include?(value)
55
+ if all_branch_names.include?(value)
37
56
  options[:branch] = value
38
57
  else
39
58
  abort %{The branch "#{value}" could not be found.}
@@ -63,6 +82,12 @@ class Twig
63
82
  options[:property_only] ||= {}
64
83
  options[:property_only].merge!(property_hash)
65
84
 
85
+ when :property_width
86
+ set_property_width_option(value)
87
+
88
+ when :reverse
89
+ options[:reverse] = Twig::Util.truthy?(value)
90
+
66
91
  when :unset_property
67
92
  options[:unset_property] = value
68
93
  end
@@ -89,6 +114,33 @@ class Twig
89
114
  options[:header_weight] = weight if weight
90
115
  end
91
116
 
117
+ def set_property_width_option(value)
118
+ value.each do |property_name, property_value|
119
+ unless Twig::Util.numeric?(property_value)
120
+ abort %{The value `--#{property_name}-width=#{property_value}` is invalid.}
121
+ end
122
+
123
+ property_name_width = property_name.to_s.size
124
+ property_value = property_value.to_i
125
+
126
+ if property_value < [property_name_width, MIN_PROPERTY_WIDTH].max
127
+ error = %{The value `--#{property_name}-width=#{property_value}` } +
128
+ %{is too low. The minimum is }
129
+
130
+ if property_value < property_name_width
131
+ error << %{#{property_name_width} (width of "#{property_name}").}
132
+ elsif property_value < MIN_PROPERTY_WIDTH
133
+ error << %{#{MIN_PROPERTY_WIDTH}.}
134
+ end
135
+
136
+ abort error
137
+ end
138
+
139
+ options[:property_width] ||= {}
140
+ options[:property_width].merge!(property_name => property_value)
141
+ end
142
+ end
143
+
92
144
  def unset_option(key)
93
145
  options.delete(key)
94
146
  end
data/lib/twig/util.rb CHANGED
@@ -5,5 +5,9 @@ class Twig
5
5
  !!Float(value) rescue false
6
6
  end
7
7
 
8
+ def self.truthy?(value)
9
+ %w[true yes y on 1].include?(value.to_s.downcase)
10
+ end
11
+
8
12
  end
9
13
  end
data/lib/twig/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Twig
2
- VERSION = '1.2.1'
2
+ VERSION = '1.3'
3
3
  end
@@ -39,6 +39,25 @@ describe Twig::Cli do
39
39
  end
40
40
  end
41
41
 
42
+ describe '#help_description_for_custom_property' do
43
+ before :each do
44
+ @twig = Twig.new
45
+ end
46
+
47
+ it 'returns a help string for a custom property' do
48
+ option_parser = OptionParser.new
49
+ @twig.should_receive(:help_separator) do |opt_parser, desc, options|
50
+ opt_parser.should == option_parser
51
+ desc.should == " --test-option Test option description\n"
52
+ options.should == { :trailing => "\n" }
53
+ end
54
+
55
+ @twig.help_description_for_custom_property(option_parser, [
56
+ ['--test-option', 'Test option description']
57
+ ])
58
+ end
59
+ end
60
+
42
61
  describe '#help_paragraph' do
43
62
  before :each do
44
63
  @twig = Twig.new
@@ -59,13 +78,79 @@ describe Twig::Cli do
59
78
  end
60
79
  end
61
80
 
81
+ describe '#help_line_for_custom_property?' do
82
+ before :each do
83
+ @twig = Twig.new
84
+ end
85
+
86
+ it 'returns true for `--except-foo`' do
87
+ @twig.help_line_for_custom_property?(' --except-foo ').should be_true
88
+ end
89
+
90
+ it 'returns false for `--except-branch`' do
91
+ @twig.help_line_for_custom_property?(' --except-branch ').should be_false
92
+ end
93
+
94
+ it 'returns false for `--except-PROPERTY`' do
95
+ @twig.help_line_for_custom_property?(' --except-PROPERTY ').should be_false
96
+ end
97
+
98
+ it 'returns true for `--only-foo`' do
99
+ @twig.help_line_for_custom_property?(' --only-foo ').should be_true
100
+ end
101
+
102
+ it 'returns false for `--only-branch`' do
103
+ @twig.help_line_for_custom_property?(' --only-branch ').should be_false
104
+ end
105
+
106
+ it 'returns false for `--only-PROPERTY`' do
107
+ @twig.help_line_for_custom_property?(' --only-PROPERTY ').should be_false
108
+ end
109
+
110
+ it 'returns true for `--foo-width`' do
111
+ @twig.help_line_for_custom_property?(' --foo-width ').should be_true
112
+ end
113
+
114
+ it 'returns false for `--branch-width`' do
115
+ @twig.help_line_for_custom_property?(' --branch-width ').should be_false
116
+ end
117
+
118
+ it 'returns false for `--PROPERTY-width`' do
119
+ @twig.help_line_for_custom_property?(' --PROPERTY-width ').should be_false
120
+ end
121
+ end
122
+
62
123
  describe '#read_cli_options!' do
63
124
  before :each do
64
125
  @twig = Twig.new
65
126
  end
66
127
 
128
+ it 'recognizes `--unset` and sets an `:unset_property` option' do
129
+ @twig.options[:unset_property].should be_nil # Precondition
130
+ @twig.read_cli_options!(%w[--unset test])
131
+ @twig.options[:unset_property].should == 'test'
132
+ end
133
+
134
+ it 'recognizes `--help` and prints the help content' do
135
+ help_lines = []
136
+ @twig.stub(:puts) { |message| help_lines << message.strip }
137
+ @twig.should_receive(:exit)
138
+
139
+ @twig.read_cli_options!(['--help'])
140
+
141
+ help_lines.should include("Twig v#{Twig::VERSION}")
142
+ help_lines.should include('http://rondevera.github.io/twig/')
143
+ end
144
+
145
+ it 'recognizes `--version` and prints the current version' do
146
+ @twig.should_receive(:puts).with(Twig::VERSION)
147
+ @twig.should_receive(:exit)
148
+
149
+ @twig.read_cli_options!(['--version'])
150
+ end
151
+
67
152
  it 'recognizes `-b` and sets a `:branch` option' do
68
- @twig.should_receive(:branch_names).and_return(['test'])
153
+ @twig.should_receive(:all_branch_names).and_return(['test'])
69
154
  @twig.options[:branch].should be_nil # Precondition
70
155
 
71
156
  @twig.read_cli_options!(%w[-b test])
@@ -74,7 +159,7 @@ describe Twig::Cli do
74
159
  end
75
160
 
76
161
  it 'recognizes `--branch` and sets a `:branch` option' do
77
- @twig.should_receive(:branch_names).and_return(['test'])
162
+ @twig.should_receive(:all_branch_names).and_return(['test'])
78
163
  @twig.options[:branch].should be_nil # Precondition
79
164
 
80
165
  @twig.read_cli_options!(%w[--branch test])
@@ -190,17 +275,19 @@ describe Twig::Cli do
190
275
  @twig.options[:property_only].should be_nil
191
276
  end
192
277
 
193
- it 'recognizes `--unset` and sets an `:unset_property` option' do
194
- @twig.options[:unset_property].should be_nil # Precondition
195
- @twig.read_cli_options!(%w[--unset test])
196
- @twig.options[:unset_property].should == 'test'
278
+ it 'recognizes `--branch-width`' do
279
+ @twig.options[:property_width].should be_nil
280
+ @twig.should_receive(:set_option).with(:property_width, :branch => '10')
281
+
282
+ @twig.read_cli_options!(%w[--branch-width 10])
197
283
  end
198
284
 
199
- it 'recognizes `--version` and prints the current version' do
200
- @twig.should_receive(:puts).with(Twig::VERSION)
201
- @twig.should_receive(:exit)
285
+ it 'recognizes `--<property>-width`' do
286
+ Twig::Branch.stub(:all_properties) { %w[foo] }
287
+ @twig.options[:property_width].should be_nil
288
+ @twig.should_receive(:set_option).with(:property_width, :foo => '10')
202
289
 
203
- @twig.read_cli_options!(['--version'])
290
+ @twig.read_cli_options!(%w[--foo-width 10])
204
291
  end
205
292
 
206
293
  it 'recognizes `--header-style`' do
@@ -211,6 +298,12 @@ describe Twig::Cli do
211
298
  @twig.options[:header_weight].should == :bold
212
299
  end
213
300
 
301
+ it 'recognizes `--reverse`' do
302
+ @twig.options[:reverse].should be_nil
303
+ @twig.read_cli_options!(['--reverse'])
304
+ @twig.options[:reverse].should be_true
305
+ end
306
+
214
307
  it 'handles invalid options' do
215
308
  @twig.should_receive(:abort_for_option_exception) do |exception|
216
309
  exception.should be_a(OptionParser::InvalidOption)
@@ -311,7 +404,7 @@ describe Twig::Cli do
311
404
  end
312
405
 
313
406
  it 'gets a property for a specified branch' do
314
- @twig.should_receive(:branch_names).and_return([@branch_name])
407
+ @twig.should_receive(:all_branch_names).and_return([@branch_name])
315
408
  @twig.set_option(:branch, @branch_name)
316
409
  @twig.should_receive(:get_branch_property_for_cli).
317
410
  with(@branch_name, @property_name)
@@ -337,7 +430,7 @@ describe Twig::Cli do
337
430
  end
338
431
 
339
432
  it 'sets a property for a specified branch' do
340
- @twig.should_receive(:branch_names).and_return([@branch_name])
433
+ @twig.should_receive(:all_branch_names).and_return([@branch_name])
341
434
  @twig.set_option(:branch, @branch_name)
342
435
  @twig.should_receive(:set_branch_property_for_cli).
343
436
  with(@branch_name, @property_name, @property_value).
@@ -364,7 +457,7 @@ describe Twig::Cli do
364
457
  end
365
458
 
366
459
  it 'unsets a property for a specified branch' do
367
- @twig.should_receive(:branch_names).and_return([@branch_name])
460
+ @twig.should_receive(:all_branch_names).and_return([@branch_name])
368
461
  @twig.set_option(:branch, @branch_name)
369
462
  @twig.should_receive(:unset_branch_property_for_cli).
370
463
  with(@branch_name, @property_name)
@@ -7,23 +7,15 @@ describe Twig::Display do
7
7
 
8
8
  describe '#column' do
9
9
  it 'returns a string with an exact fixed width' do
10
- @twig.column('foo', 1, :width => 8).should == 'foo' + (' ' * 5)
10
+ @twig.column('foo', :width => 8).should == 'foo' + (' ' * 5)
11
11
  end
12
12
 
13
13
  it 'returns a string that fits a column exactly' do
14
- @twig.column('asdfasdf', 1, :width => 8).should == 'asdf... '
14
+ @twig.column('asdfasdf', :width => 8).should == 'asdfasdf'
15
15
  end
16
16
 
17
17
  it 'truncates a wide string with an ellipsis' do
18
- @twig.column('asdfasdfasdf', 1, :width => 8).should == 'asdf... '
19
- end
20
-
21
- it 'returns a string that spans multiple columns' do
22
- @twig.column('foo', 2, :width => 8).should == 'foo' + (' ' * 13)
23
- end
24
-
25
- it 'returns a string that spans multiple columns and is truncated' do
26
- @twig.column('asdf' * 5, 2, :width => 8).should == 'asdfasdfasdf... '
18
+ @twig.column('asdfasdfasdf', :width => 8).should == 'asdfa...'
27
19
  end
28
20
 
29
21
  it 'passes options through to `format_string`' do
@@ -31,7 +23,52 @@ describe Twig::Display do
31
23
  @twig.should_receive(:format_string).
32
24
  with('foo' + (' ' * 5), format_options)
33
25
 
34
- @twig.column('foo', 1, format_options)
26
+ @twig.column('foo', format_options)
27
+ end
28
+ end
29
+
30
+ describe '#property_column_width' do
31
+ it 'returns a default width if no property name is given' do
32
+ @twig.property_column_width.should ==
33
+ Twig::Display::DEFAULT_PROPERTY_COLUMN_WIDTH
34
+ end
35
+
36
+ context 'with no custom column widths set' do
37
+ before :each do
38
+ @twig.options[:property_width].should be_nil
39
+ end
40
+
41
+ it 'returns a default width if a property name is given' do
42
+ @twig.property_column_width(:foo).should ==
43
+ Twig::Display::DEFAULT_PROPERTY_COLUMN_WIDTH
44
+ end
45
+
46
+ it 'returns a default width if :branch is given' do
47
+ @twig.property_column_width(:branch).should ==
48
+ Twig::Display::DEFAULT_BRANCH_COLUMN_WIDTH
49
+ end
50
+ end
51
+
52
+ context 'with custom column widths set' do
53
+ it 'returns a default width if a property name is given but it has no custom width' do
54
+ @twig.property_column_width(:baz).should ==
55
+ Twig::Display::DEFAULT_PROPERTY_COLUMN_WIDTH
56
+ end
57
+
58
+ it 'returns a custom width if a property name is given and it has a custom width' do
59
+ @twig.set_option(:property_width, :foo => 20)
60
+ @twig.property_column_width(:foo).should == 20
61
+ end
62
+
63
+ it 'returns a default width if :branch is given but it has no custom width' do
64
+ @twig.property_column_width(:branch).should ==
65
+ Twig::Display::DEFAULT_BRANCH_COLUMN_WIDTH
66
+ end
67
+
68
+ it 'returns a custom width if :branch is given but it has no custom width' do
69
+ @twig.set_option(:property_width, :branch => 20)
70
+ @twig.property_column_width(:branch).should == 20
71
+ end
35
72
  end
36
73
  end
37
74
 
@@ -44,17 +81,36 @@ describe Twig::Display do
44
81
  result = @twig.branch_list_headers({})
45
82
  result_lines = result.split("\n")
46
83
 
47
- column_width = 8
48
- columns_for_date_time = 5
49
- first_column_width = column_width * columns_for_date_time
50
- result_lines[0].should == (' ' * first_column_width) +
51
- 'foo ' + (' ' * column_width) +
52
- 'quux ' + (' ' * column_width) +
53
- ' branch' + (' ' * column_width)
54
- result_lines[1].should == (' ' * first_column_width) +
55
- '--- ' + (' ' * column_width) +
56
- '---- ' + (' ' * column_width) +
57
- ' ------' + (' ' * column_width)
84
+ date_time_column_width = 35
85
+ extra_property_column_width = 8
86
+ column_gutter = @twig.column_gutter
87
+ result_lines[0].should == (' ' * date_time_column_width) + column_gutter +
88
+ 'foo ' + (' ' * extra_property_column_width) + column_gutter +
89
+ 'quux ' + (' ' * extra_property_column_width) + column_gutter +
90
+ ' branch'
91
+ result_lines[1].should == (' ' * date_time_column_width) + column_gutter +
92
+ '--- ' + (' ' * extra_property_column_width) + column_gutter +
93
+ '---- ' + (' ' * extra_property_column_width) + column_gutter +
94
+ ' ------'
95
+ end
96
+
97
+ it 'sets a header width' do
98
+ @twig.set_option(:property_width, :foo => 4)
99
+
100
+ result = @twig.branch_list_headers({})
101
+ result_lines = result.split("\n")
102
+
103
+ date_time_column_width = 35
104
+ extra_property_column_width = 8
105
+ column_gutter = @twig.column_gutter
106
+ result_lines[0].should == (' ' * date_time_column_width) + column_gutter +
107
+ 'foo ' + column_gutter +
108
+ 'quux ' + (' ' * extra_property_column_width) + column_gutter +
109
+ ' branch'
110
+ result_lines[1].should == (' ' * date_time_column_width) + column_gutter +
111
+ '--- ' + column_gutter +
112
+ '---- ' + (' ' * extra_property_column_width) + column_gutter +
113
+ ' ------'
58
114
  end
59
115
 
60
116
  it 'sets a header color' do
@@ -146,6 +202,58 @@ describe Twig::Display do
146
202
 
147
203
  result.should include('line breaks')
148
204
  end
205
+
206
+ it 'returns a line with custom column widths' do
207
+ branch = Twig::Branch.new('other-branch')
208
+ branch.should_receive(:last_commit_time).and_return(@commit_time)
209
+ @twig.set_option(:property_width, :foo => 5)
210
+
211
+ result = @twig.branch_list_line(branch)
212
+
213
+ column_gutter = @twig.column_gutter
214
+ result.should ==
215
+ '2000-01-01' + (' ' * 25) + column_gutter +
216
+ 'foo! ' + column_gutter +
217
+ 'bar!' + (' ' * 12) + column_gutter +
218
+ ' ' + branch.name
219
+ end
220
+
221
+ context 'with a custom width for the branch column' do
222
+ before :each do
223
+ @twig.set_option(:property_width, :branch => 8)
224
+ end
225
+
226
+ it 'returns a line for the current branch' do
227
+ indicator = Twig::Display::CURRENT_BRANCH_INDICATOR
228
+ branch = Twig::Branch.new('my-branch')
229
+ branch_regexp = /#{Regexp.escape(indicator)}#{Regexp.escape(branch.name)}/
230
+ branch.should_receive(:last_commit_time).and_return(@commit_time)
231
+
232
+ result = @twig.branch_list_line(branch)
233
+ unformatted_result = @twig.unformat_string(result)
234
+
235
+ column_gutter = @twig.column_gutter
236
+ unformatted_result.should ==
237
+ '2000-01-01' + (' ' * 25) + column_gutter +
238
+ 'foo!' + (' ' * 12) + column_gutter +
239
+ 'bar!' + (' ' * 12) + column_gutter +
240
+ indicator + 'my-br...'
241
+ end
242
+
243
+ it 'returns a line for a branch other than the current branch' do
244
+ branch = Twig::Branch.new('other-branch')
245
+ branch.should_receive(:last_commit_time).and_return(@commit_time)
246
+
247
+ result = @twig.branch_list_line(branch)
248
+
249
+ column_gutter = @twig.column_gutter
250
+ result.should ==
251
+ '2000-01-01' + (' ' * 25) + column_gutter +
252
+ 'foo!' + (' ' * 12) + column_gutter +
253
+ 'bar!' + (' ' * 12) + column_gutter +
254
+ ' ' + 'other...'
255
+ end
256
+ end
149
257
  end
150
258
 
151
259
  describe '#format_string' do