twig 1.6 → 1.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,5 @@
1
1
  class Twig
2
2
  module Subcommands
3
-
4
3
  BIN_PREFIX = 'twig-'
5
4
 
6
5
  def self.all_names
@@ -22,5 +21,18 @@ class Twig
22
21
  ENV['PATH'].split(':')
23
22
  end
24
23
 
24
+ def self.exec_subcommand_if_any(cli_args)
25
+ # Run subcommand binary, if any, and exit here
26
+
27
+ subcommand_name = cli_args[0]
28
+ bin_name = Twig::Subcommands::BIN_PREFIX + subcommand_name
29
+ subcommand_path = Twig.run("which #{bin_name} 2>/dev/null")
30
+ return if subcommand_path.empty?
31
+
32
+ subcommand_args = cli_args[1..-1]
33
+ command = ([subcommand_path] + subcommand_args).join(' ')
34
+
35
+ exec(command)
36
+ end
25
37
  end
26
38
  end
data/lib/twig/system.rb CHANGED
@@ -1,9 +1,7 @@
1
1
  class Twig
2
2
  module System
3
-
4
3
  def self.windows?
5
4
  RbConfig::CONFIG['host_os'] =~ /(cygwin|mingw|windows|win32)/
6
5
  end
7
-
8
6
  end
9
7
  end
data/lib/twig/util.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  class Twig
2
2
  module Util
3
-
4
3
  def self.numeric?(value)
5
4
  !!Float(value) rescue false
6
5
  end
@@ -8,6 +7,5 @@ class Twig
8
7
  def self.truthy?(value)
9
8
  %w[true yes y on 1].include?(value.to_s.downcase)
10
9
  end
11
-
12
10
  end
13
11
  end
data/lib/twig/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Twig
2
- VERSION = '1.6'
2
+ VERSION = '1.7'
3
3
  end
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,10 @@
1
1
  require 'twig'
2
2
  require 'json'
3
- require 'rspec/radar'
4
3
 
5
4
  RSpec.configure do |config|
6
- config.expect_with :rspec do |c|
7
- c.syntax = :expect
5
+ config.mock_with :rspec do |mocks|
6
+ mocks.verify_doubled_constant_names = true
7
+ mocks.verify_partial_doubles = true
8
+ mocks.yield_receiver_to_any_instance_implementation_blocks = true
8
9
  end
9
10
  end
@@ -1,5 +1,6 @@
1
1
  # encoding: UTF-8
2
2
  require 'spec_helper'
3
+ require 'shellwords'
3
4
 
4
5
  describe Twig::Branch do
5
6
  before :each do
@@ -13,16 +14,18 @@ describe Twig::Branch do
13
14
  fix_some_other_of_the_things
14
15
  fix_nothing
15
16
  ]
16
- @commit_time_strings = ['2001-01-01', '2002-02-02', '2003-03-03' ]
17
- @commit_time_agos = ['111 days ago', '2 months ago', '3 years, 3 months ago']
17
+ @commit_time_strings = %w[
18
+ 2001-01-01
19
+ 2002-02-02
20
+ 2003-03-03
21
+ ]
18
22
  @command =
19
23
  %{git for-each-ref #{Twig::REF_PREFIX} --format="#{Twig::REF_FORMAT}"}
20
24
 
21
25
  @branch_tuples = (0..2).map do |i|
22
26
  [
23
27
  @branch_names[i],
24
- @commit_time_strings[i],
25
- @commit_time_agos[i]
28
+ @commit_time_strings[i]
26
29
  ].join(Twig::REF_FORMAT_SEPARATOR)
27
30
  end.join("\n")
28
31
  end
@@ -34,15 +37,15 @@ describe Twig::Branch do
34
37
 
35
38
  expect(branches[0].name).to eq(@branch_names[0])
36
39
  expect(branches[0].last_commit_time.to_s).to match(
37
- %r{#{@commit_time_strings[0]} .* \(111d ago\)}
40
+ /#{@commit_time_strings[0]}/
38
41
  )
39
42
  expect(branches[1].name).to eq(@branch_names[1])
40
43
  expect(branches[1].last_commit_time.to_s).to match(
41
- %r{#{@commit_time_strings[1]} .* \(2mo ago\)}
44
+ /#{@commit_time_strings[1]}/
42
45
  )
43
46
  expect(branches[2].name).to eq(@branch_names[2])
44
47
  expect(branches[2].last_commit_time.to_s).to match(
45
- %r{#{@commit_time_strings[2]} .* \(3y ago\)}
48
+ /#{@commit_time_strings[2]}/
46
49
  )
47
50
  end
48
51
 
@@ -144,6 +147,26 @@ describe Twig::Branch do
144
147
  end
145
148
  end
146
149
 
150
+ describe '.shellescape_property_value' do
151
+ it 'escapes backticks' do
152
+ value = 'value_`ls`'
153
+ result = Twig::Branch.shellescape_property_value(value)
154
+ expect(result).to eql('value_\`ls\`')
155
+ end
156
+
157
+ it 'escapes dollar signs' do
158
+ value = 'value_$PATH'
159
+ result = Twig::Branch.shellescape_property_value(value)
160
+ expect(result).to eql('value_\$PATH')
161
+ end
162
+
163
+ it 'does not escape spaces' do
164
+ value = 'foo bar'
165
+ result = Twig::Branch.shellescape_property_value(value)
166
+ expect(result).to eql('foo bar')
167
+ end
168
+ end
169
+
147
170
  describe '#initialize' do
148
171
  it 'requires a name' do
149
172
  branch = Twig::Branch.new('test')
@@ -155,7 +178,7 @@ describe Twig::Branch do
155
178
  end
156
179
 
157
180
  it 'accepts a last commit time' do
158
- commit_time = Twig::CommitTime.new(Time.now, '99 days ago')
181
+ commit_time = Twig::CommitTime.new(Time.now)
159
182
  branch = Twig::Branch.new('test', :last_commit_time => commit_time)
160
183
  expect(branch.last_commit_time).to eq(commit_time)
161
184
  end
@@ -172,7 +195,7 @@ describe Twig::Branch do
172
195
  before :each do
173
196
  @branch = Twig::Branch.new('test')
174
197
  time = Time.parse('2000-01-01 18:30 UTC')
175
- commit_time = Twig::CommitTime.new(time, '')
198
+ commit_time = Twig::CommitTime.new(time)
176
199
  @time_string = time.iso8601
177
200
  allow(@branch).to receive(:last_commit_time) { commit_time }
178
201
  end
@@ -207,6 +230,24 @@ describe Twig::Branch do
207
230
  end
208
231
  end
209
232
 
233
+ describe '#parent_name' do
234
+ before :each do
235
+ @branch = Twig::Branch.new('test')
236
+ end
237
+
238
+ it 'returns the parent branch name' do
239
+ parent_name = 'parent'
240
+ allow(@branch).to receive(:get_property).with('diff-branch').and_return(parent_name)
241
+
242
+ expect(@branch.parent_name).to eq(parent_name)
243
+ end
244
+
245
+ it 'returns nil if the parent branch is unknown' do
246
+ allow(@branch).to receive(:get_property).with('diff-branch')
247
+ expect(@branch.parent_name).to be_nil
248
+ end
249
+ end
250
+
210
251
  describe '#sanitize_property' do
211
252
  before :each do
212
253
  @branch = Twig::Branch.new('test')
@@ -259,6 +300,7 @@ describe Twig::Branch do
259
300
  branch = Twig::Branch.new('utf8_{・ิω・ิ}')
260
301
  properties = { 'test1' => 'value1' }
261
302
  git_result = "branch.#{branch}.test1 value1"
303
+ expect(Shellwords).to receive(:escape).with(branch.to_s) { branch.to_s }
262
304
  expect(Twig).to receive(:run).
263
305
  with(%{git config --get-regexp "branch.#{branch}.(test1)$"}).
264
306
  and_return(git_result)
@@ -322,7 +364,7 @@ describe Twig::Branch do
322
364
  end
323
365
 
324
366
  expect(expected_exception.message).to eq(
325
- Twig::Branch::EMPTY_PROPERTY_NAME_ERROR
367
+ Twig::Branch::EmptyPropertyNameError::DEFAULT_MESSAGE
326
368
  )
327
369
  end
328
370
  end
@@ -403,7 +445,7 @@ describe Twig::Branch do
403
445
  end
404
446
 
405
447
  expect(expected_exception.message).to eq(
406
- Twig::Branch::EMPTY_PROPERTY_NAME_ERROR
448
+ Twig::Branch::EmptyPropertyNameError::DEFAULT_MESSAGE
407
449
  )
408
450
  end
409
451
 
@@ -483,6 +525,37 @@ describe Twig::Branch do
483
525
  %{Saved property "#{property}" as "#{value}" for branch "#{@branch}"}
484
526
  )
485
527
  end
528
+
529
+ it 'sets a property for a branch whose name contains a backtick' do
530
+ branch = Twig::Branch.new('branch_`ls`')
531
+ property = 'test'
532
+ value = 'value'
533
+ escaped_branch_name = branch.to_s.shellescape
534
+ expect(Twig).to receive(:run).
535
+ with(%{git config branch.#{escaped_branch_name}.#{property} "#{value}"}) do
536
+ `(exit 0)`; value # Set `$?` to `0`
537
+ end
538
+
539
+ result = branch.set_property(property, value)
540
+ expect(result).to include(
541
+ %{Saved property "#{property}" as "#{value}" for branch "#{branch}"}
542
+ )
543
+ end
544
+
545
+ it 'sets a property value that contains special shell characters' do
546
+ property = 'test'
547
+ value = 'value `ls` $PATH'
548
+ escaped_value = 'value \`ls\` \$PATH'
549
+ expect(Twig).to receive(:run).
550
+ with(%{git config branch.#{@branch}.#{property} "#{escaped_value}"}) do
551
+ `(exit 0)`; value # Set `$?` to `0`
552
+ end
553
+
554
+ result = @branch.set_property(property, value)
555
+ expect(result).to include(
556
+ %{Saved property "#{property}" as "#{value}" for branch "#{@branch}"}
557
+ )
558
+ end
486
559
  end
487
560
 
488
561
  describe '#unset_property' do
@@ -519,7 +592,6 @@ describe Twig::Branch do
519
592
 
520
593
  it 'raises an error if the property name is an empty string' do
521
594
  bad_property = ' '
522
- property = ''
523
595
  expect(@branch).not_to receive(:get_property)
524
596
  expect(Twig).not_to receive(:run)
525
597
 
@@ -530,7 +602,7 @@ describe Twig::Branch do
530
602
  end
531
603
 
532
604
  expect(expected_exception.message).to eq(
533
- Twig::Branch::EMPTY_PROPERTY_NAME_ERROR
605
+ Twig::Branch::EmptyPropertyNameError::DEFAULT_MESSAGE
534
606
  )
535
607
  end
536
608
 
@@ -548,6 +620,21 @@ describe Twig::Branch do
548
620
  %{The branch "#{@branch}" does not have the property "#{property}"}
549
621
  )
550
622
  end
623
+
624
+ it 'unsets a property for a branch whose name contains a backtick' do
625
+ branch = Twig::Branch.new('branch_`ls`')
626
+ property = 'test'
627
+ expect(branch).to receive(:get_property).
628
+ with(property).and_return('value')
629
+ expect(Twig).to receive(:run).with(
630
+ %{git config --unset branch.#{branch.to_s.shellescape}.#{property}}
631
+ )
632
+
633
+ result = branch.unset_property(property)
634
+ expect(result).to include(
635
+ %{Removed property "#{property}" for branch "#{branch}"}
636
+ )
637
+ end
551
638
  end
552
639
 
553
640
  end
@@ -0,0 +1,187 @@
1
+ require 'spec_helper'
2
+
3
+ describe Twig::Cli::Help do
4
+ Help = Twig::Cli::Help
5
+
6
+ describe '.description' do
7
+ before :each do
8
+ @twig = Twig.new
9
+ end
10
+
11
+ it 'returns short text in a single line' do
12
+ text = 'The quick brown fox.'
13
+ result = Help.description(text, :width => 80)
14
+ expect(result).to eq([text])
15
+ end
16
+
17
+ it 'returns long text in a string with line breaks' do
18
+ text = 'The quick brown fox jumps over the lazy, lazy dog.'
19
+ result = Help.description(text, :width => 20)
20
+ expect(result).to eq([
21
+ 'The quick brown fox',
22
+ 'jumps over the lazy,',
23
+ 'lazy dog.'
24
+ ])
25
+ end
26
+
27
+ it 'breaks a long word by max line length' do
28
+ text = 'Thequickbrownfoxjumpsoverthelazydog.'
29
+ result = Help.description(text, :width => 20)
30
+ expect(result).to eq([
31
+ 'Thequickbrownfoxjump',
32
+ 'soverthelazydog.'
33
+ ])
34
+ end
35
+
36
+ it 'adds a blank line' do
37
+ text = 'The quick brown fox.'
38
+ result = Help.description(text, :width => 80, :add_blank_line => true)
39
+ expect(result).to eq([text, ' '])
40
+ end
41
+ end
42
+
43
+ describe '.description_for_custom_property' do
44
+ before :each do
45
+ @twig = Twig.new
46
+ end
47
+
48
+ it 'returns a help string for a custom property' do
49
+ option_parser = OptionParser.new
50
+ expect(Help).to receive(:print_section) do |opt_parser, desc, options|
51
+ expect(opt_parser).to eq(option_parser)
52
+ expect(desc).to eq(" --test-option Test option description\n")
53
+ expect(options).to eq(:trailing => "\n")
54
+ end
55
+
56
+ Help.description_for_custom_property(option_parser, [
57
+ ['--test-option', 'Test option description']
58
+ ])
59
+ end
60
+
61
+ it 'supports custom trailing whitespace' do
62
+ option_parser = OptionParser.new
63
+ expect(Help).to receive(:print_section) do |opt_parser, desc, options|
64
+ expect(opt_parser).to eq(option_parser)
65
+ expect(desc).to eq(" --test-option Test option description\n")
66
+ expect(options).to eq(:trailing => '')
67
+ end
68
+
69
+ Help.description_for_custom_property(option_parser, [
70
+ ['--test-option', 'Test option description']
71
+ ], :trailing => '')
72
+ end
73
+ end
74
+
75
+ describe '.line_for_custom_property?' do
76
+ before :each do
77
+ @twig = Twig.new
78
+ end
79
+
80
+ it 'returns true for `--except-foo`' do
81
+ expect(Help.line_for_custom_property?(' --except-foo ')).to eql(true)
82
+ end
83
+
84
+ it 'returns false for `--except-branch`' do
85
+ expect(Help.line_for_custom_property?(' --except-branch ')).to be_falsy
86
+ end
87
+
88
+ it 'returns false for `--except-property`' do
89
+ expect(Help.line_for_custom_property?(' --except-property ')).to be_falsy
90
+ end
91
+
92
+ it 'returns false for `--except-PROPERTY`' do
93
+ expect(Help.line_for_custom_property?(' --except-PROPERTY ')).to be_falsy
94
+ end
95
+
96
+ it 'returns true for `--only-foo`' do
97
+ expect(Help.line_for_custom_property?(' --only-foo ')).to eql(true)
98
+ end
99
+
100
+ it 'returns false for `--only-branch`' do
101
+ expect(Help.line_for_custom_property?(' --only-branch ')).to be_falsy
102
+ end
103
+
104
+ it 'returns false for `--only-property`' do
105
+ expect(Help.line_for_custom_property?(' --only-property ')).to be_falsy
106
+ end
107
+
108
+ it 'returns false for `--only-PROPERTY`' do
109
+ expect(Help.line_for_custom_property?(' --only-PROPERTY ')).to be_falsy
110
+ end
111
+
112
+ it 'returns true for `--foo-width`' do
113
+ expect(Help.line_for_custom_property?(' --foo-width ')).to eql(true)
114
+ end
115
+
116
+ it 'returns false for `--branch-width`' do
117
+ expect(Help.line_for_custom_property?(' --branch-width ')).to be_falsy
118
+ end
119
+
120
+ it 'returns false for `--PROPERTY-width`' do
121
+ expect(Help.line_for_custom_property?(' --PROPERTY-width ')).to be_falsy
122
+ end
123
+ end
124
+
125
+ describe '.paragraph' do
126
+ before :each do
127
+ @twig = Twig.new
128
+ end
129
+
130
+ it 'returns long text in a paragraph with line breaks' do
131
+ text = Array.new(5) do
132
+ 'The quick brown fox jumps over the lazy dog.'
133
+ end.join(' ')
134
+
135
+ result = Help.paragraph(text)
136
+
137
+ expect(result).to eq([
138
+ 'The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the',
139
+ 'lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps',
140
+ 'over the lazy dog. The quick brown fox jumps over the lazy dog.'
141
+ ].join("\n"))
142
+ end
143
+ end
144
+
145
+ describe '.subcommand_descriptions' do
146
+ it 'returns a word-wrapped list of subcommand descriptions' do
147
+ output_lines = Help.subcommand_descriptions
148
+
149
+ # Some lines are actually multi-line descriptions. Split them so we can
150
+ # count characters per line.
151
+ output_lines = output_lines.map { |line| line.split("\n") }.flatten
152
+
153
+ output_line_max_width = output_lines.map { |line| line.length }.max
154
+ expect(output_line_max_width).to be <= Help.console_width
155
+ end
156
+ end
157
+
158
+ describe '.header' do
159
+ it 'generates a header section' do
160
+ option_parser = double
161
+ text = 'Some header'
162
+ expected_text = "Some header\n==========="
163
+ expect(Help).to receive(:print_section).with(
164
+ option_parser,
165
+ expected_text,
166
+ :trailing => "\n\n"
167
+ )
168
+
169
+ Help.header(option_parser, text)
170
+ end
171
+ end
172
+
173
+ describe '.subheader' do
174
+ it 'generates a subheader section' do
175
+ option_parser = double
176
+ text = 'Some subheader'
177
+ expected_text = "Some subheader\n--------------"
178
+ expect(Help).to receive(:print_section).with(
179
+ option_parser,
180
+ expected_text,
181
+ :trailing => "\n\n"
182
+ )
183
+
184
+ Help.subheader(option_parser, text)
185
+ end
186
+ end
187
+ end