twig 1.1 → 1.2

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/HISTORY.md CHANGED
@@ -1,6 +1,17 @@
1
1
  Twig
2
2
  ====
3
3
 
4
+ 1.2 (2013-03-21)
5
+ ----------------
6
+ * ENHANCEMENT: Add `--only-<property>` and `--except-<property>` options for
7
+ filtering custom properties by value.
8
+ * ENHANCEMENT: Simplify setup for writing GitHub-related Twig subcommands.
9
+ * FIX: Fix showing `twig --help` outside of a Git repository. (GH-16. Thanks
10
+ [ryangreenberg](https://github.com/ryangreenberg)!)
11
+ * FIX: Fix showing `twig --version` outside of a Git repository.
12
+ * FIX: Fix the project's homepage URL in `twig --help`. (GH-17. Thanks
13
+ [ryangreenberg](https://github.com/ryangreenberg)!)
14
+
4
15
  1.1 (2013-03-06)
5
16
  ----------------
6
17
  * ENHANCEMENT: Add branch name tab completion for `-b` and `--branch` options.
data/README.md CHANGED
@@ -52,14 +52,18 @@ Filtering branches
52
52
  ------------------
53
53
 
54
54
  Twig lists all of your branches by default (newest first), but you can filter
55
- them by name and age:
55
+ them by age, name, and custom properties:
56
56
 
57
+ * `twig --max-days-old <age>`:
58
+ Only list branches below a given age
57
59
  * `twig --only-branch <pattern>`:
58
60
  Only list branches whose name matches a given pattern
59
61
  * `twig --except-branch <pattern>`:
60
62
  Don't list branches whose name matches a given pattern
61
- * `twig --max-days-old <age>`:
62
- Only list branches below a given age
63
+ * `twig --only-<property> <pattern>`:
64
+ Only list branches with a given property that matches a given pattern
65
+ * `twig --except-<property> <pattern>`:
66
+ Don't list branches with a given property that matches a given pattern
63
67
  * `twig --all`:
64
68
  List all branches regardless of other filtering options
65
69
 
data/bin/twig CHANGED
@@ -3,7 +3,11 @@
3
3
  require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'twig'))
4
4
 
5
5
  twig = Twig.new
6
- abort unless twig.repo?
6
+ repo_required = ARGV != ['--help'] && ARGV != ['help'] && ARGV != ['--version']
7
+
8
+ if repo_required && !twig.repo?
9
+ abort "Current directory is not a git repository."
10
+ end
7
11
 
8
12
  # Gettin' twiggy wit' it.
9
13
  twig.read_config_file!
@@ -4,37 +4,10 @@
4
4
  #
5
5
  # Author: Ron DeVera <http://rondevera.com>
6
6
 
7
- class TwigGithubRepo
8
- def initialize
9
- if origin_url.empty? || username.empty? || repository.empty?
10
- abort_for_non_github_repo
11
- end
7
+ require 'rubygems'
8
+ require 'twig/github'
12
9
 
13
- yield(self)
14
- end
15
-
16
- def origin_url
17
- @origin_url ||= `git config remote.origin.url`.strip
18
- end
19
-
20
- def origin_url_parts
21
- @origin_url_parts ||= origin_url.split(/[\/:]/)
22
- end
23
-
24
- def username
25
- @username ||= origin_url_parts[-2] || ''
26
- end
27
-
28
- def repository
29
- @repo ||= origin_url_parts[-1].sub(/\.git$/, '') || ''
30
- end
31
-
32
- def abort_for_non_github_repo
33
- abort 'This does not appear to be a GitHub repository.'
34
- end
35
- end
36
-
37
- TwigGithubRepo.new do |gh_repo|
10
+ Twig::GithubRepo.new do |gh_repo|
38
11
  url = "https://github.com/#{gh_repo.username}/#{gh_repo.repository}"
39
12
  puts "GitHub URL: #{url}"
40
13
  `which open && open #{url}`
@@ -11,37 +11,7 @@
11
11
  require 'rubygems'
12
12
  require 'twig'
13
13
 
14
- class TwigGithubRepo
15
- def initialize
16
- if origin_url.empty? || username.empty? || repository.empty?
17
- abort_for_non_github_repo
18
- end
19
-
20
- yield(self)
21
- end
22
-
23
- def origin_url
24
- @origin_url ||= `git config remote.origin.url`.strip
25
- end
26
-
27
- def origin_url_parts
28
- @origin_url_parts ||= origin_url.split(/[\/:]/)
29
- end
30
-
31
- def username
32
- @username ||= origin_url_parts[-2] || ''
33
- end
34
-
35
- def repository
36
- @repo ||= origin_url_parts[-1].sub(/\.git$/, '') || ''
37
- end
38
-
39
- def abort_for_non_github_repo
40
- abort 'This does not appear to be a GitHub repository.'
41
- end
42
- end
43
-
44
- TwigGithubRepo.new do |gh_repo|
14
+ Twig::GithubRepo.new do |gh_repo|
45
15
  twig = Twig.new
46
16
  twig.read_cli_options!(ARGV)
47
17
  branch_name = twig.options[:branch] || twig.current_branch_name
@@ -10,41 +10,11 @@ require 'json'
10
10
  require 'net/https'
11
11
  require 'uri'
12
12
 
13
- class TwigGithubRepo
14
- def initialize
15
- if origin_url.empty? || username.empty? || repository.empty?
16
- abort_for_non_github_repo
17
- end
18
-
19
- yield(self)
20
- end
21
-
22
- def origin_url
23
- @origin_url ||= `git config remote.origin.url`.strip
24
- end
25
-
26
- def origin_url_parts
27
- @origin_url_parts ||= origin_url.split(/[\/:]/)
28
- end
29
-
30
- def username
31
- @username ||= origin_url_parts[-2] || ''
32
- end
33
-
34
- def repository
35
- @repo ||= origin_url_parts[-1].sub(/\.git$/, '') || ''
36
- end
37
-
38
- def abort_for_non_github_repo
39
- abort 'This does not appear to be a GitHub repository.'
40
- end
41
- end
42
-
43
13
  twig = Twig.new
44
14
  twig.read_config_file!
45
15
  twig.read_cli_options!(ARGV)
46
16
 
47
- TwigGithubRepo.new do |gh_repo|
17
+ Twig::GithubRepo.new do |gh_repo|
48
18
  $stdout.sync = true
49
19
  print 'Getting latest states for GitHub issues...'
50
20
 
@@ -26,7 +26,7 @@ class Twig
26
26
  end
27
27
 
28
28
  def repo?
29
- Twig.run('git rev-parse')
29
+ Twig.run('git rev-parse 2>&1')
30
30
  $?.success?
31
31
  end
32
32
 
@@ -57,15 +57,30 @@ class Twig
57
57
  max_seconds_old = options[:max_days_old] * 86400 if options[:max_days_old]
58
58
 
59
59
  branches.select do |branch|
60
- if max_seconds_old
61
- seconds_old = now.to_i - branch.last_commit_time.to_i
62
- next if seconds_old > max_seconds_old
60
+ catch :skip_branch do
61
+ if max_seconds_old
62
+ seconds_old = now.to_i - branch.last_commit_time.to_i
63
+ next if seconds_old > max_seconds_old
64
+ end
65
+
66
+ (options[:property_except] || {}).each do |property_name, property_value|
67
+ if property_name == :branch
68
+ throw :skip_branch if branch.name =~ property_value
69
+ elsif branch.get_property(property_name.to_s) =~ property_value
70
+ throw :skip_branch
71
+ end
72
+ end
73
+
74
+ (options[:property_only] || {}).each do |property_name, property_value|
75
+ if property_name == :branch
76
+ throw :skip_branch if branch.name !~ property_value
77
+ elsif branch.get_property(property_name.to_s) !~ property_value
78
+ throw :skip_branch
79
+ end
80
+ end
81
+
82
+ true
63
83
  end
64
-
65
- next if options[:branch_except] && branch.name =~ options[:branch_except]
66
- next if options[:branch_only] && branch.name !~ options[:branch_only]
67
-
68
- true
69
84
  end
70
85
  end
71
86
 
@@ -19,7 +19,7 @@ class Twig
19
19
 
20
20
  #{intro}
21
21
 
22
- https://rondevera.github.com/twig
22
+ http://rondevera.github.com/twig
23
23
 
24
24
  BANNER
25
25
  end
@@ -37,8 +37,8 @@ class Twig
37
37
  # Split words into lines
38
38
  while words.any?
39
39
  current_word = words.shift
40
- current_word_size = formatted_string_display_size(current_word)
41
- last_line_size = lines.last && formatted_string_display_size(lines.last)
40
+ current_word_size = unformat_string(current_word).size
41
+ last_line_size = lines.last && unformat_string(lines.last).size
42
42
 
43
43
  if last_line_size && (last_line_size + current_word_size + 1 <= width)
44
44
  lines.last << ' ' << current_word
@@ -82,7 +82,26 @@ class Twig
82
82
 
83
83
  desc = 'Show this help content.'
84
84
  opts.on('--help', *help_description(desc)) do
85
- puts opts; exit
85
+ summary_lines = opts.to_a
86
+
87
+ # Filter out `--only-PROPERTY` lines
88
+ summary_lines.each do |line|
89
+ is_custom_property_only = (
90
+ line.include?('--only-') &&
91
+ !line.include?('--only-branch') &&
92
+ !line.include?('--only-PROPERTY')
93
+ )
94
+ is_custom_property_except = (
95
+ line.include?('--except-') &&
96
+ !line.include?('--except-branch') &&
97
+ !line.include?('--except-PROPERTY')
98
+ )
99
+ unless is_custom_property_only || is_custom_property_except
100
+ puts line
101
+ end
102
+ end
103
+
104
+ exit
86
105
  end
87
106
 
88
107
  desc = 'Show Twig version.'
@@ -94,37 +113,62 @@ class Twig
94
113
 
95
114
  help_separator(opts, 'Filtering branches:')
96
115
 
116
+ desc = 'Only list branches below a given age.'
117
+ opts.on(
118
+ '--max-days-old AGE', *help_description(desc, :add_separator => true)
119
+ ) do |age|
120
+ set_option(:max_days_old, age)
121
+ end
122
+
97
123
  desc = 'Only list branches whose name matches a given pattern.'
98
124
  opts.on(
99
125
  '--only-branch PATTERN',
100
126
  *help_description(desc, :add_separator => true)
101
127
  ) do |pattern|
102
- set_option(:branch_only, pattern)
128
+ set_option(:property_only, :branch => pattern)
103
129
  end
104
130
 
105
131
  desc = 'Do not list branches whose name matches a given pattern.'
106
132
  opts.on(
107
133
  '--except-branch PATTERN',
108
- *help_description(desc, :add_separator => true)
134
+ *help_description(desc, :add_separator => false)
135
+ # `:add_separator => false` skips the extra line generated by the
136
+ # custom property filters below.
109
137
  ) do |pattern|
110
- set_option(:branch_except, pattern)
138
+ set_option(:property_except, :branch => pattern)
111
139
  end
112
140
 
113
- desc = 'Only list branches below a given age.'
114
- opts.on(
115
- '--max-days-old AGE', *help_description(desc, :add_separator => true)
116
- ) do |age|
117
- set_option(:max_days_old, age)
141
+ custom_properties = Twig::Branch.all_properties
142
+ custom_properties.each do |property_name|
143
+ opts.on("--only-#{property_name} PATTERN") do |pattern|
144
+ set_option(:property_only, property_name.to_sym => pattern)
145
+ end
146
+
147
+ opts.on("--except-#{property_name} PATTERN") do |pattern|
148
+ set_option(:property_except, property_name.to_sym => pattern)
149
+ end
118
150
  end
119
151
 
152
+ custom_properties_desc_lines = [
153
+ ['--only-PROPERTY PATTERN', 'Only list branches with a given property'],
154
+ ['', 'that matches a given pattern.'],
155
+ ['', ''],
156
+ ['--except-PROPERTY PATTERN', 'Do not list branches with a given property'],
157
+ ['', 'that matches a given pattern.']
158
+ ]
159
+ custom_properties_desc = custom_properties_desc_lines.inject('') do |desc, line_parts|
160
+ desc + sprintf(' %-29s', line_parts[0]) + line_parts[1] + "\n"
161
+ end
162
+ help_separator(opts, custom_properties_desc, :trailing => "\n")
163
+
120
164
  desc =
121
- 'Lists all branches regardless of age or name options. ' +
165
+ 'Lists all branches regardless of other filtering options. ' +
122
166
  'Useful for overriding options in ' +
123
167
  File.basename(Twig::Options::CONFIG_FILE) + '.'
124
168
  opts.on('--all', *help_description(desc)) do |pattern|
125
169
  unset_option(:max_days_old)
126
- unset_option(:branch_except)
127
- unset_option(:branch_only)
170
+ unset_option(:property_except)
171
+ unset_option(:property_only)
128
172
  end
129
173
 
130
174
 
@@ -171,7 +215,11 @@ class Twig
171
215
 
172
216
  option_parser.parse!(args)
173
217
  rescue OptionParser::InvalidOption, OptionParser::MissingArgument => exception
174
- puts exception.to_s
218
+ abort_for_option_exception(exception)
219
+ end
220
+
221
+ def abort_for_option_exception(exception)
222
+ puts exception.message
175
223
  puts 'For a list of options, run `twig --help`.'
176
224
  exit
177
225
  end
@@ -200,36 +248,49 @@ class Twig
200
248
  # Get/set branch property
201
249
  if property_value
202
250
  # `$ twig <key> <value>`
203
- begin
204
- puts set_branch_property(branch_name, property_name, property_value)
205
- rescue ArgumentError, RuntimeError => exception
206
- abort exception.message
207
- end
251
+ set_branch_property_for_cli(branch_name, property_name, property_value)
208
252
  else
209
253
  # `$ twig <key>`
210
- begin
211
- value = get_branch_property(branch_name, property_name)
212
- if value
213
- puts value
214
- else
215
- abort %{The branch "#{branch_name}" does not have the property "#{property_name}".}
216
- end
217
- rescue ArgumentError => exception
218
- abort exception.message
219
- end
254
+ get_branch_property_for_cli(branch_name, property_name)
220
255
  end
221
256
  elsif property_to_unset
222
257
  # `$ twig --unset <key>`
223
- begin
224
- puts unset_branch_property(branch_name, property_to_unset)
225
- rescue ArgumentError, Twig::Branch::MissingPropertyError => exception
226
- abort exception.message
227
- end
258
+ unset_branch_property_for_cli(branch_name, property_to_unset)
228
259
  else
229
260
  # `$ twig`
230
261
  puts list_branches
231
262
  end
232
263
  end
233
264
 
265
+ def get_branch_property_for_cli(branch_name, property_name)
266
+ begin
267
+ value = get_branch_property(branch_name, property_name)
268
+ if value
269
+ puts value
270
+ else
271
+ raise Twig::Branch::MissingPropertyError,
272
+ %{The branch "#{branch_name}" does not have the property "#{property_name}".}
273
+ end
274
+ rescue ArgumentError, Twig::Branch::MissingPropertyError => exception
275
+ abort exception.message
276
+ end
277
+ end
278
+
279
+ def set_branch_property_for_cli(branch_name, property_name, property_value)
280
+ begin
281
+ puts set_branch_property(branch_name, property_name, property_value)
282
+ rescue ArgumentError, RuntimeError => exception
283
+ abort exception.message
284
+ end
285
+ end
286
+
287
+ def unset_branch_property_for_cli(branch_name, property_name)
288
+ begin
289
+ puts unset_branch_property(branch_name, property_name)
290
+ rescue ArgumentError, Twig::Branch::MissingPropertyError => exception
291
+ abort exception.message
292
+ end
293
+ end
294
+
234
295
  end
235
296
  end
@@ -125,8 +125,8 @@ class Twig
125
125
  "\e[#{string_options.join(';')}m#{string}\e[0m"
126
126
  end
127
127
 
128
- def formatted_string_display_size(string)
129
- string.gsub(/\e\[[0-9]+(;[0-9]+)?m/, '').size
128
+ def unformat_string(string)
129
+ string.gsub(/\e\[[0-9]+(;[0-9]+)?m/, '')
130
130
  end
131
131
  end # module Display
132
132
  end
@@ -0,0 +1,36 @@
1
+ class Twig
2
+ class GithubRepo
3
+ def self.run(command)
4
+ # Duplicated from `Twig.run` for making lightweight subcommands.
5
+ `#{command}`.strip
6
+ end
7
+
8
+ def initialize
9
+ if origin_url.empty? || username.empty? || repository.empty?
10
+ abort_for_non_github_repo
11
+ end
12
+
13
+ yield(self)
14
+ end
15
+
16
+ def origin_url
17
+ @origin_url ||= Twig::GithubRepo.run('git config remote.origin.url')
18
+ end
19
+
20
+ def origin_url_parts
21
+ @origin_url_parts ||= origin_url.split(/[\/:]/)
22
+ end
23
+
24
+ def username
25
+ @username ||= origin_url_parts[-2] || ''
26
+ end
27
+
28
+ def repository
29
+ @repo ||= origin_url_parts[-1].sub(/\.git$/, '') || ''
30
+ end
31
+
32
+ def abort_for_non_github_repo
33
+ abort 'This does not appear to be a GitHub repository.'
34
+ end
35
+ end
36
+ end