twig 1.6 → 1.7

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.
@@ -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