jtag 0.1.7 → 0.1.15
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.
- checksums.yaml +7 -0
- data/bin/jtag +313 -60
- data/lib/jtag.rb +3 -3
- data/lib/jtag/config_files/config.yml +2 -0
- data/lib/jtag/jekylltag.rb +83 -16
- data/lib/jtag/version.rb +1 -1
- metadata +44 -50
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3e151ce3931cae97e33b988fbb68d8f11d061b6082533675c9d77523a4a8f0d5
|
4
|
+
data.tar.gz: 4533ce25468f2c79e6a847656a60d73e6bd5c262339604d7be95932cf60e6f29
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: afe50224a4bd699348a3fe249030b2b7cd990c0a3862fa8362be80ee27bf1a59b348af3fa4e451ec24a021a4a8278fd8cae55a1dac46abfdacad14773b461cfb
|
7
|
+
data.tar.gz: 2298a87e7d680f2a9a2f411af69106095ca3c9d2c5b181d8ca8eb96cb467911e9ed8efe0cb70a1c51bdf80f9d1f62a47e8ca8f48fd29c6c457af885ba6e258bd
|
data/bin/jtag
CHANGED
@@ -22,19 +22,33 @@ end
|
|
22
22
|
desc 'Debug level'
|
23
23
|
default_value '0'
|
24
24
|
arg_name 'debug_level'
|
25
|
-
flag [:d,:debug]
|
25
|
+
flag [:d,:debug], :must_match => /\d+/, :type => Integer, :default_value => 0
|
26
26
|
|
27
27
|
desc 'Run silently'
|
28
|
-
switch [:s
|
28
|
+
switch [:s,:silent]
|
29
29
|
|
30
|
-
desc
|
30
|
+
desc 'Perform case-insensitive matches and searches'
|
31
|
+
switch [:i,:case_insensitive]
|
32
|
+
|
33
|
+
desc "Test (dry run, don't update files)"
|
31
34
|
long_desc "Run all commands and show results on the command line, but don't overwrite/update any files"
|
32
35
|
default_value false
|
33
|
-
switch [:t
|
36
|
+
switch [:t,:test]
|
34
37
|
|
35
38
|
def console_log(msg="", options={})
|
36
|
-
return if @silent
|
37
39
|
err = options[:err] || false
|
40
|
+
options[:log] ||= false
|
41
|
+
|
42
|
+
if options[:log]
|
43
|
+
if err
|
44
|
+
@log.warn(msg)
|
45
|
+
else
|
46
|
+
@log.info(msg)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
return if @silent
|
51
|
+
|
38
52
|
unless err
|
39
53
|
$stdout.puts msg
|
40
54
|
else
|
@@ -93,10 +107,10 @@ desc 'List tags, optionally filter for keywords/regular expressions (OR)'
|
|
93
107
|
long_desc 'This command can be used to find the exact format for a given tag to keep spaces, underscores, capitalization and pluralization consistent'
|
94
108
|
arg_name 'keyword', :multiple
|
95
109
|
command :search do |c|
|
96
|
-
c.desc 'Format to use when outputting tags to console: list, json, csv or yaml. Defaults to yaml.'
|
110
|
+
c.desc 'Format to use when outputting tags to console: list, json, plist, csv or yaml. Defaults to yaml.'
|
97
111
|
c.arg_name 'output_format'
|
98
112
|
c.default_value 'yaml'
|
99
|
-
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json)$/i, :type => String
|
113
|
+
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json|plist)$/i, :type => String
|
100
114
|
|
101
115
|
c.desc 'Include tag counts'
|
102
116
|
c.arg_name 'counts'
|
@@ -106,8 +120,8 @@ command :search do |c|
|
|
106
120
|
c.action do |global_options,options,args|
|
107
121
|
tags = @jt.get_tags({:counts => true})
|
108
122
|
if args.length > 0
|
123
|
+
re = args.join("|")
|
109
124
|
tags.delete_if {|tag|
|
110
|
-
re = args.join("|")
|
111
125
|
if tag && tag['name'] =~ /(#{re})/i
|
112
126
|
false
|
113
127
|
else
|
@@ -119,7 +133,7 @@ command :search do |c|
|
|
119
133
|
else
|
120
134
|
tags.map! {|tag| tag['name'] }
|
121
135
|
end
|
122
|
-
output_tags(tags,options[:format])
|
136
|
+
output_tags(tags,{ :format => options[:format] })
|
123
137
|
else
|
124
138
|
tags.delete_if {|tag| !tag }
|
125
139
|
if options[:c]
|
@@ -127,18 +141,199 @@ command :search do |c|
|
|
127
141
|
else
|
128
142
|
tags.map! {|tag| tag['name'] }
|
129
143
|
end
|
130
|
-
output_tags(tags,options[:format])
|
144
|
+
output_tags(tags,{ :format => options[:format] })
|
131
145
|
end
|
132
146
|
end
|
133
147
|
end
|
134
148
|
|
149
|
+
desc 'List posts with tag(s)'
|
150
|
+
arg_name 'tags', :multiple
|
151
|
+
command :posts_tagged do |c|
|
152
|
+
c.desc 'Boolean operator for multiple tags (AND/OR/NOT)'
|
153
|
+
c.arg_name 'bool'
|
154
|
+
c.default_value 'OR'
|
155
|
+
c.flag [:b,:bool], :must_match => /(AND|OR|NOT)/i, :type => String
|
156
|
+
|
157
|
+
c.desc 'Format to use when outputting file list: list, json, plist, csv or yaml. Defaults to list.'
|
158
|
+
c.arg_name 'output_format'
|
159
|
+
c.default_value 'list'
|
160
|
+
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json|plist)$/, :type => String
|
161
|
+
|
162
|
+
c.desc 'If output format is list, print without newlines.'
|
163
|
+
c.switch [:print0]
|
164
|
+
|
165
|
+
c.action do |global_options,options,args|
|
166
|
+
bool = options[:bool].upcase
|
167
|
+
files = []
|
168
|
+
tags = []
|
169
|
+
matches = []
|
170
|
+
args.length.times do
|
171
|
+
arg = args.pop
|
172
|
+
if File.exists?(arg)
|
173
|
+
files.push(arg)
|
174
|
+
else
|
175
|
+
tags.push(arg)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
if files.empty?
|
179
|
+
if @jt.default_post_location && File.exists?(File.dirname(@jt.default_post_location))
|
180
|
+
files = Dir.glob(@jt.default_post_location)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
exit_now! "No valid filename in arguments" if files.empty?
|
184
|
+
files.each {|file|
|
185
|
+
if File.exists?(file)
|
186
|
+
post_tags = @jt.post_tags(file)
|
187
|
+
|
188
|
+
if bool == "AND"
|
189
|
+
matched = 0
|
190
|
+
tags.each {|tag|
|
191
|
+
matched += 1 if post_tags.include?(tag)
|
192
|
+
}
|
193
|
+
matches.push(file) if matched == tags.length
|
194
|
+
elsif bool == "NOT"
|
195
|
+
matched = false
|
196
|
+
tags.each {|tag|
|
197
|
+
matched = true if post_tags.include?(tag)
|
198
|
+
}
|
199
|
+
matches.push(file) unless matched
|
200
|
+
else
|
201
|
+
tags.each {|tag|
|
202
|
+
if post_tags.include?(tag)
|
203
|
+
matches.push(file) unless matches.include?(file)
|
204
|
+
end
|
205
|
+
}
|
206
|
+
end
|
207
|
+
else
|
208
|
+
raise "File not found: #{file}"
|
209
|
+
end
|
210
|
+
}
|
211
|
+
|
212
|
+
search_string = tags.join(" #{bool} ")
|
213
|
+
if matches.empty?
|
214
|
+
console_log "No matching files found for #{search_string}"
|
215
|
+
else
|
216
|
+
console_log "(#{search_string})", {:err => true}
|
217
|
+
output_tags(matches, { :format => options[:format], :print0 => options[:print0], :grouping => "files" })
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
desc 'Show tags with fewer than X posts attached to them, optionally removing them from specified posts'
|
223
|
+
arg_name 'file_pattern', :multiple
|
224
|
+
command :loners do |c|
|
225
|
+
c.desc 'Format to use when outputting tags to console: list, json, plist, csv or yaml. Defaults to yaml.'
|
226
|
+
c.arg_name 'output_format'
|
227
|
+
c.default_value 'yaml'
|
228
|
+
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json|plist)$/, :type => String
|
229
|
+
|
230
|
+
c.desc 'Upper limit for how many posts a tag can be attached to and still be a loner'
|
231
|
+
c.arg_name 'max'
|
232
|
+
c.default_value '2'
|
233
|
+
c.flag [:m,:max], :default_value => 2, :must_match => /^\d+$/
|
234
|
+
|
235
|
+
c.desc "Remove tags with fewer than X posts attached"
|
236
|
+
c.switch [:r,:remove], :default_value => false
|
237
|
+
|
238
|
+
c.desc "Display output without attached occurence counts"
|
239
|
+
c.switch [:no_counts], :default_value => false
|
240
|
+
|
241
|
+
c.desc 'Output a file list of tags that can be edited and passed back in for removing'
|
242
|
+
c.arg_name 'filename'
|
243
|
+
c.flag [:e,:edit], :default_value => false, :type => String
|
244
|
+
|
245
|
+
c.action do |global_options,options,args|
|
246
|
+
max = options[:m].to_i
|
247
|
+
loner_tags = @jt.get_tags({:counts => true})
|
248
|
+
loner_tags.delete_if { |tag|
|
249
|
+
tag.class == FalseClass || tag['count'] > max
|
250
|
+
}
|
251
|
+
loner_tags.sort_by! {|tag| tag['count']}
|
252
|
+
|
253
|
+
exit_now! "No tags matched the criteria" if loner_tags.empty? || loner_tags.nil?
|
254
|
+
|
255
|
+
if options[:e]
|
256
|
+
path = File.expand_path(options[:e])
|
257
|
+
while File.exists?(path)
|
258
|
+
if path =~ /(\d+)(\.[^\.]+?)?$/
|
259
|
+
path.sub!(/(\d+)(\.[^\.]+?)?$/) do |m|
|
260
|
+
$1.next! + $2
|
261
|
+
end
|
262
|
+
else
|
263
|
+
path.sub!(/(\.[^\.]+?)?$/,'01\1')
|
264
|
+
end
|
265
|
+
end
|
266
|
+
File.open(path, 'w+') do |f|
|
267
|
+
f.puts "# Edit this file to remove tags you want to keep,"
|
268
|
+
f.puts "# then run `jtag remove -p '#{path}' [/path/to/posts/*.md]`"
|
269
|
+
f.puts "# to remove any tags left in the file."
|
270
|
+
f.puts "#"
|
271
|
+
f.puts "# The post counts are included for your convenience, and will"
|
272
|
+
f.puts "# be automatically ignored when reading the list back in."
|
273
|
+
f.puts "#"
|
274
|
+
f.puts "# Lines beginning with a # are comments (ignored), but you probably figured that out."
|
275
|
+
loner_tags.each{ |t|
|
276
|
+
f.printf "% 3d |\t%s\n", t['count'], t['name']
|
277
|
+
}
|
278
|
+
end
|
279
|
+
|
280
|
+
console_log "A list of results and instructions for use have been written to #{path}."
|
281
|
+
if ENV['EDITOR']
|
282
|
+
console_log
|
283
|
+
print "Would you like to open the file in #{ENV['EDITOR']} now? (y/N) "
|
284
|
+
input = STDIN.gets
|
285
|
+
if input =~ /^y/i
|
286
|
+
system "#{ENV['EDITOR']} '#{path}'"
|
287
|
+
end
|
288
|
+
end
|
289
|
+
elsif options[:r]
|
290
|
+
files = []
|
291
|
+
args.length.times do
|
292
|
+
arg = args.pop
|
293
|
+
files.push(arg) if File.exists?(arg)
|
294
|
+
end
|
295
|
+
if files.empty?
|
296
|
+
if @jt.default_post_location && File.exists?(File.dirname(@jt.default_post_location))
|
297
|
+
files = Dir.glob(@jt.default_post_location)
|
298
|
+
end
|
299
|
+
end
|
300
|
+
exit_now! "No valid filename in arguments" if files.empty?
|
301
|
+
files.each {|file|
|
302
|
+
tags = @jt.post_tags(file)
|
303
|
+
loner_tags.each { |d|
|
304
|
+
tags.delete_if { |tag|
|
305
|
+
if global_options[:i]
|
306
|
+
tag.downcase == d.downcase
|
307
|
+
else
|
308
|
+
tag == d
|
309
|
+
end
|
310
|
+
}
|
311
|
+
}
|
312
|
+
unless global_options[:t]
|
313
|
+
@jt.update_file_tags(file,tags)
|
314
|
+
console_log "Updated tags for #{file}", :log => true
|
315
|
+
end
|
316
|
+
|
317
|
+
console_log
|
318
|
+
console_log File.basename(file) + ":"
|
319
|
+
output_tags(tags, :format => options[:format], :filename => file )
|
320
|
+
}
|
321
|
+
else
|
322
|
+
output_tags(loner_tags.map{|tag|
|
323
|
+
count = options[:no_counts] ? "" : " (#{tag['count']})"
|
324
|
+
"#{tag['name']}#{count}"}, :format => options[:format] )
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
|
135
330
|
desc 'Show the current tags for posts'
|
136
|
-
arg_name '
|
331
|
+
arg_name 'file_pattern', :multiple
|
137
332
|
command :tags do |c|
|
138
|
-
c.desc 'Format to use when outputting tags to console: list, json, csv or yaml. Defaults to yaml.'
|
333
|
+
c.desc 'Format to use when outputting tags to console: list, json, plist, csv or yaml. Defaults to yaml.'
|
139
334
|
c.arg_name 'output_format'
|
140
335
|
c.default_value 'yaml'
|
141
|
-
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json)$/, :type => String
|
336
|
+
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json|plist)$/, :type => String
|
142
337
|
|
143
338
|
c.action do |global_options,options,args|
|
144
339
|
|
@@ -151,7 +346,7 @@ command :tags do |c|
|
|
151
346
|
if tags.empty? || tags.nil?
|
152
347
|
console_log "No tags in post", {:err => true}
|
153
348
|
else
|
154
|
-
output_tags(tags,options[:format])
|
349
|
+
output_tags(tags,{ :format => options[:format] })
|
155
350
|
end
|
156
351
|
end
|
157
352
|
args.each{|file|
|
@@ -164,7 +359,7 @@ command :tags do |c|
|
|
164
359
|
if tags.empty? || tags.nil?
|
165
360
|
console_log "No tags in post", {:err => true}
|
166
361
|
else
|
167
|
-
output_tags(tags,options[:format])
|
362
|
+
output_tags(tags,{ :format => options[:format], :filename => file })
|
168
363
|
end
|
169
364
|
else
|
170
365
|
raise "File not found: #{file}"
|
@@ -175,12 +370,12 @@ end
|
|
175
370
|
|
176
371
|
|
177
372
|
desc 'Sort the existing tags for posts'
|
178
|
-
arg_name '
|
373
|
+
arg_name 'file_pattern', :multiple
|
179
374
|
command :sort do |c|
|
180
|
-
c.desc 'Format to use when outputting tags to console: list, json, csv or yaml. Defaults to yaml.'
|
375
|
+
c.desc 'Format to use when outputting tags to console: list, json, plist, csv or yaml. Defaults to yaml.'
|
181
376
|
c.arg_name 'output_format'
|
182
377
|
c.default_value 'yaml'
|
183
|
-
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json)$/, :type => String
|
378
|
+
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json|plist)$/, :type => String
|
184
379
|
|
185
380
|
c.action do |global_options,options,args|
|
186
381
|
args.each{|file|
|
@@ -190,14 +385,13 @@ command :sort do |c|
|
|
190
385
|
unless global_options[:t]
|
191
386
|
@jt.update_file_tags(file, tags)
|
192
387
|
end
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
end
|
388
|
+
console_log
|
389
|
+
console_log File.basename(file) + ":"
|
390
|
+
|
197
391
|
if tags.empty? || tags.nil?
|
198
392
|
console_log "No tags in post", {:err => true}
|
199
393
|
else
|
200
|
-
output_tags(tags,options[:format])
|
394
|
+
output_tags(tags,{ :format => options[:format], :filename => file })
|
201
395
|
end
|
202
396
|
}
|
203
397
|
end
|
@@ -207,10 +401,10 @@ desc 'Merge multiple tags into one'
|
|
207
401
|
long_desc 'Scans the specified posts for any of the tags, merging any found into the last one in the list'
|
208
402
|
arg_name 'tags to merge merge_tag'
|
209
403
|
command :merge do |c|
|
210
|
-
c.desc 'Format to use when outputting tags to console: list, json, csv or yaml. Defaults to yaml.'
|
404
|
+
c.desc 'Format to use when outputting tags to console: list, json, plist, csv or yaml. Defaults to yaml.'
|
211
405
|
c.arg_name 'output_format'
|
212
406
|
c.default_value 'yaml'
|
213
|
-
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json)$/, :type => String
|
407
|
+
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json|plist)$/, :type => String
|
214
408
|
|
215
409
|
c.action do |global_options, options, args|
|
216
410
|
files = []
|
@@ -220,11 +414,15 @@ command :merge do |c|
|
|
220
414
|
if File.exists?(arg)
|
221
415
|
files.push(arg)
|
222
416
|
else
|
223
|
-
exit_now! "No valid filename in arguments" if files.empty?
|
224
417
|
tags.push(arg)
|
225
418
|
end
|
226
419
|
end
|
227
|
-
|
420
|
+
if files.empty?
|
421
|
+
if @jt.default_post_location && File.exists?(File.dirname(@jt.default_post_location))
|
422
|
+
files = Dir.glob(@jt.default_post_location)
|
423
|
+
end
|
424
|
+
end
|
425
|
+
exit_now! "No valid filename in arguments" if files.empty?
|
228
426
|
exit_now! "Needs at least two tag inputs, one or more to merge, one to merge to" if tags.length < 2
|
229
427
|
tags.reverse!
|
230
428
|
merge_tag = tags.pop
|
@@ -235,11 +433,13 @@ command :merge do |c|
|
|
235
433
|
unless global_options[:t]
|
236
434
|
@jt.update_file_tags(file, new_tags)
|
237
435
|
console_log
|
238
|
-
console_log "Updated tags for #{file}"
|
436
|
+
console_log "Updated tags for #{file}", :log => true
|
239
437
|
end
|
438
|
+
|
240
439
|
console_log
|
241
440
|
console_log File.basename(file) + ":"
|
242
|
-
output_tags(new_tags,options[:format])
|
441
|
+
output_tags(new_tags,{ :format => options[:format], :filename => file })
|
442
|
+
|
243
443
|
}
|
244
444
|
end
|
245
445
|
end
|
@@ -264,11 +464,12 @@ end
|
|
264
464
|
|
265
465
|
desc 'Add tags to post(s)'
|
266
466
|
arg_name 'tags', :multiple
|
467
|
+
arg_name 'file_pattern'
|
267
468
|
command :add do |c|
|
268
|
-
c.desc 'Format to use when outputting tags to console: list, json, csv or yaml. Defaults to yaml.'
|
469
|
+
c.desc 'Format to use when outputting tags to console: list, json, plist, csv or yaml. Defaults to yaml.'
|
269
470
|
c.arg_name 'output_format'
|
270
471
|
c.default_value 'yaml'
|
271
|
-
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json)$/, :type => String
|
472
|
+
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json|plist)$/, :type => String
|
272
473
|
|
273
474
|
|
274
475
|
c.action do |global_options,options,args|
|
@@ -279,11 +480,15 @@ command :add do |c|
|
|
279
480
|
if File.exists?(arg)
|
280
481
|
files.push(arg)
|
281
482
|
else
|
282
|
-
exit_now! "No valid filename in arguments" if files.empty?
|
283
483
|
new_tags.push(arg)
|
284
484
|
end
|
285
485
|
end
|
286
|
-
|
486
|
+
if files.empty?
|
487
|
+
if @jt.default_post_location && File.exists?(File.dirname(@jt.default_post_location))
|
488
|
+
files = Dir.glob(@jt.default_post_location)
|
489
|
+
end
|
490
|
+
end
|
491
|
+
exit_now! "No valid filename in arguments" if files.empty?
|
287
492
|
exit_now! "No tags found in arguments" if new_tags.empty?
|
288
493
|
|
289
494
|
files.each {|file|
|
@@ -293,12 +498,12 @@ command :add do |c|
|
|
293
498
|
tags.sort!
|
294
499
|
unless global_options[:t]
|
295
500
|
@jt.update_file_tags(file,tags)
|
296
|
-
console_log "Updated tags for #{file}"
|
501
|
+
console_log "Updated tags for #{file}", :log => true
|
297
502
|
end
|
298
503
|
|
299
504
|
console_log
|
300
505
|
console_log File.basename(file) + ":"
|
301
|
-
output_tags(tags,options[:format])
|
506
|
+
output_tags(tags, :format => options[:format], :filename => file)
|
302
507
|
}
|
303
508
|
end
|
304
509
|
end
|
@@ -306,10 +511,15 @@ end
|
|
306
511
|
desc 'Remove tags from post(s)'
|
307
512
|
arg_name 'tags', :multiple
|
308
513
|
command :remove do |c|
|
309
|
-
c.desc 'Format to use when outputting tags to console: list, json, csv or yaml. Defaults to yaml.'
|
514
|
+
c.desc 'Format to use when outputting tags to console: list, json, plist, csv or yaml. Defaults to yaml.'
|
310
515
|
c.arg_name 'output_format'
|
311
516
|
c.default_value 'yaml'
|
312
|
-
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json)$/, :type => String
|
517
|
+
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json|plist)$/, :type => String
|
518
|
+
|
519
|
+
c.desc 'A filepath to a list of tags to be removed'
|
520
|
+
c.long_desc 'One tag per line, and leading numbers and pipes (|) will be ignored. This file format is generated automatically by the `loners` command, but any text file will do the trick.'
|
521
|
+
c.arg_name 'input_file'
|
522
|
+
c.flag [:p,:path], :type => String
|
313
523
|
|
314
524
|
c.action do |global_options,options,args|
|
315
525
|
files = []
|
@@ -319,37 +529,60 @@ command :remove do |c|
|
|
319
529
|
if File.exists?(arg)
|
320
530
|
files.push(arg)
|
321
531
|
else
|
322
|
-
|
323
|
-
remove_tags.push(arg)
|
532
|
+
remove_tags.push(arg) unless options[:p]
|
324
533
|
end
|
325
534
|
end
|
535
|
+
if files.empty?
|
536
|
+
if @jt.default_post_location && File.exists?(File.dirname(@jt.default_post_location))
|
537
|
+
files = Dir.glob(@jt.default_post_location)
|
538
|
+
end
|
539
|
+
end
|
540
|
+
exit_now! "No valid filename in arguments" if files.empty?
|
541
|
+
|
542
|
+
if options[:p]
|
543
|
+
path = File.expand_path(options[:p])
|
544
|
+
exit_now! "Input file does not appear to be where you think it is." unless File.exists?(path)
|
545
|
+
IO.read(path).each_line {|l|
|
546
|
+
next if l =~ /^\s*#/
|
547
|
+
if l =~ /^(?:[\s\d])*(?:\|\s*)?(\S.*?)$/
|
548
|
+
remove_tags.push($1.strip)
|
549
|
+
end
|
550
|
+
}
|
551
|
+
console_log "Found #{remove_tags.length} tags in #{File.basename(path)}..."
|
552
|
+
end
|
326
553
|
|
327
|
-
exit_now! "No tags found in
|
554
|
+
exit_now! "No tags found in input, my work here is done" if remove_tags.empty?
|
328
555
|
|
329
556
|
files.each {|file|
|
330
557
|
tags = @jt.post_tags(file)
|
331
558
|
remove_tags.each { |d|
|
332
|
-
tags.delete_if { |tag|
|
559
|
+
tags.delete_if { |tag|
|
560
|
+
if global_options[:i]
|
561
|
+
tag.downcase == d.downcase
|
562
|
+
else
|
563
|
+
tag == d
|
564
|
+
end
|
565
|
+
}
|
333
566
|
}
|
334
567
|
unless global_options[:t]
|
335
568
|
@jt.update_file_tags(file,tags)
|
336
|
-
console_log "Updated tags for #{file}"
|
569
|
+
console_log "Updated tags for #{file}", :log => true
|
337
570
|
end
|
338
571
|
|
339
572
|
console_log
|
340
573
|
console_log File.basename(file) + ":"
|
341
|
-
output_tags(tags,options[:format])
|
574
|
+
output_tags(tags,{ :format => options[:format], :filename => file })
|
342
575
|
}
|
343
576
|
end
|
344
577
|
end
|
345
578
|
|
346
579
|
desc 'Generate a list of recommended tags, optionally updating the file'
|
347
|
-
arg_name '
|
580
|
+
arg_name 'file_pattern', :multiple
|
348
581
|
command :tag do |c|
|
349
|
-
c.desc 'Format to use when outputting tags to console: list, json, csv or yaml. Defaults to yaml.'
|
582
|
+
c.desc 'Format to use when outputting tags to console: list, json, plist, csv or yaml. Defaults to yaml.'
|
350
583
|
c.arg_name 'output_format'
|
351
584
|
c.default_value 'yaml'
|
352
|
-
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json)$/, :type => String
|
585
|
+
c.flag [:f,:format], :must_match => /^(csv|list|yaml|json|plist)$/, :type => String
|
353
586
|
|
354
587
|
c.action do |global_options,options,args|
|
355
588
|
if @piped_content
|
@@ -357,9 +590,9 @@ command :tag do |c|
|
|
357
590
|
if !global_options[:s] || global_options[:t]
|
358
591
|
if args.length > 1
|
359
592
|
console_log
|
360
|
-
console_log "STDIN:",
|
593
|
+
console_log "STDIN:", :err => true
|
361
594
|
end
|
362
|
-
output_tags(suggestions,options[:format])
|
595
|
+
output_tags(suggestions, :format => options[:format], :filename => file )
|
363
596
|
end
|
364
597
|
end
|
365
598
|
args.each {|file|
|
@@ -370,18 +603,18 @@ command :tag do |c|
|
|
370
603
|
unless global_options[:t]
|
371
604
|
if @jt.update_file_tags(file, suggestions)
|
372
605
|
console_log
|
373
|
-
console_log "Updated file #{file} with:"
|
606
|
+
console_log "Updated file #{file} with:", :log => true
|
374
607
|
else
|
375
608
|
console_log
|
376
|
-
console_log "Failed to update #{file} with:"
|
609
|
+
console_log "Failed to update #{file} with:", :log => true
|
377
610
|
end
|
378
611
|
end
|
379
612
|
if !global_options[:s] || global_options[:t]
|
380
613
|
if args.length > 1
|
381
614
|
console_log
|
382
|
-
console_log File.basename(file) + ":",
|
615
|
+
console_log File.basename(file) + ":", :err => true, :log => true
|
383
616
|
end
|
384
|
-
output_tags(suggestions,options[:format])
|
617
|
+
output_tags(suggestions, :format => options[:format], :filename => file )
|
385
618
|
end
|
386
619
|
suggestions = nil
|
387
620
|
else
|
@@ -391,19 +624,38 @@ command :tag do |c|
|
|
391
624
|
end
|
392
625
|
end
|
393
626
|
|
394
|
-
def output_tags(tags,
|
627
|
+
def output_tags(tags,options)
|
628
|
+
format = options[:format] || 'yaml'
|
629
|
+
print0 = options[:print0] || false
|
630
|
+
filename = options[:filename] || false
|
395
631
|
case format
|
396
632
|
when 'list'
|
397
|
-
|
633
|
+
unless print0
|
634
|
+
console_log tags.join("\n")
|
635
|
+
else
|
636
|
+
console_log tags.map {|tag|
|
637
|
+
if tag.strip =~ /\b\s\b/
|
638
|
+
%Q{"#{tag.strip}"}
|
639
|
+
else
|
640
|
+
tag.strip
|
641
|
+
end
|
642
|
+
}.join(" ")
|
643
|
+
end
|
398
644
|
when 'csv'
|
399
645
|
console_log tags.to_csv
|
400
646
|
when 'json'
|
401
647
|
out = {}
|
402
648
|
out['tags'] = tags
|
649
|
+
out['path'] = filename if filename
|
403
650
|
console_log out.to_json
|
404
|
-
|
651
|
+
when 'plist'
|
405
652
|
out = {}
|
406
|
-
out['
|
653
|
+
out['path'] = filename if filename
|
654
|
+
console_log tags.to_plist
|
655
|
+
else
|
656
|
+
out = {}
|
657
|
+
options[:grouping] ||= "tags"
|
658
|
+
out[options[:grouping]] = tags
|
407
659
|
console_log out.to_yaml
|
408
660
|
end
|
409
661
|
end
|
@@ -419,16 +671,17 @@ end
|
|
419
671
|
# end
|
420
672
|
|
421
673
|
pre do |global,command,options,args|
|
422
|
-
# Pre logic here
|
423
|
-
# Return true to proceed; false to abort and not call the
|
424
|
-
# chosen command
|
425
674
|
# Use skips_pre before a command to skip this block
|
426
675
|
# on that command only
|
427
676
|
@silent = global[:silent]
|
428
677
|
|
678
|
+
@logfile = File.open(File.join(Dir.tmpdir, "jtag_actions.log"), 'a')
|
679
|
+
|
680
|
+
@log = Logger.new(@logfile, shift_age = 7, shift_size = 1048576)
|
681
|
+
|
429
682
|
unless config_files_complete?
|
430
683
|
write_config
|
431
|
-
console_log "Missing config files written to #{@config_target}. Please check your configuration."
|
684
|
+
console_log "Missing config files written to #{@config_target}. Please check your configuration.", {:err => true}
|
432
685
|
return false
|
433
686
|
end
|
434
687
|
|
data/lib/jtag.rb
CHANGED
@@ -4,10 +4,10 @@ require 'fileutils'
|
|
4
4
|
require 'yaml'
|
5
5
|
require 'csv'
|
6
6
|
require 'json'
|
7
|
+
require 'plist'
|
7
8
|
require 'jtag/version.rb'
|
8
9
|
require 'jtag/string.rb'
|
9
10
|
require 'jtag/porter_stemming.rb'
|
10
11
|
require 'jtag/jekylltag.rb'
|
11
|
-
|
12
|
-
|
13
|
-
# you just need to require this one file in your bin file
|
12
|
+
require 'tmpdir'
|
13
|
+
require 'logger'
|
data/lib/jtag/jekylltag.rb
CHANGED
@@ -1,13 +1,32 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
|
2
3
|
class JTag
|
4
|
+
attr_reader :default_post_location
|
5
|
+
attr_accessor :tags_key
|
3
6
|
|
4
7
|
def initialize(support_dir, config)
|
5
8
|
@support = support_dir
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
+
begin
|
10
|
+
@tags_loc = config['tags_location']
|
11
|
+
@tags_loc.sub!(/^https?:\/\//,'')
|
12
|
+
rescue
|
13
|
+
raise "No tags location in configuration."
|
14
|
+
end
|
15
|
+
@min_matches = config['min_matches'] || 2
|
16
|
+
@tags_key = config['tags_key'] || 'tags'
|
17
|
+
|
18
|
+
if config.has_key? 'default_post_location'
|
19
|
+
@default_post_location = File.expand_path(config['default_post_location']) || false
|
20
|
+
else
|
21
|
+
console_log "#{color('yellow')}No #{color('boldyellow')}default_post_location#{color('yellow')} set.", :err => true
|
22
|
+
console_log "If you commonly work on the same posts you can add the path and *.ext", :err => true
|
23
|
+
console_log "to this key in ~/.jtag/config.yml. Then, if you don't specify files", :err => true
|
24
|
+
console_log "to act on in a command, it will fall back to those. Nice!#{color('default')}", :err => true
|
25
|
+
@default_post_location = false
|
26
|
+
end
|
27
|
+
@blacklistfile = File.join(@support,'blacklist.txt')
|
9
28
|
@blacklist = IO.read(@blacklistfile).split("\n") || []
|
10
|
-
@skipwords = IO.read(File.join(support_dir,
|
29
|
+
@skipwords = IO.read(File.join(support_dir,'stopwords.txt')).split("\n") || []
|
11
30
|
remote_tags = get_tags
|
12
31
|
@tags = {}
|
13
32
|
remote_tags.each {|tag| @tags[Text::PorterStemming.stem(tag).downcase] = tag if tag}
|
@@ -21,13 +40,14 @@ class JTag
|
|
21
40
|
counts = options[:counts] || false
|
22
41
|
host, path = @tags_loc.match(/^([^\/]+)(\/.*)/)[1,2]
|
23
42
|
tags = ""
|
24
|
-
http = Net::HTTP.new(host, 80)
|
25
|
-
http.start do |http|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
43
|
+
# http = Net::HTTP.new(host, 80)
|
44
|
+
# http.start do |http|
|
45
|
+
# request = Net::HTTP::Get.new(path)
|
46
|
+
# response = http.request(request)
|
47
|
+
# response.value
|
48
|
+
# tags = response.body
|
49
|
+
# end
|
50
|
+
tags = `curl -sSL "#{@tags_loc}"`
|
31
51
|
tags = JSON.parse(tags)
|
32
52
|
if tags && tags.key?("tags")
|
33
53
|
if counts
|
@@ -72,11 +92,11 @@ class JTag
|
|
72
92
|
[yaml, after]
|
73
93
|
end
|
74
94
|
|
75
|
-
def post_tags(file,piped=false)
|
95
|
+
def post_tags(file, piped=false)
|
76
96
|
begin
|
77
97
|
input = piped ? file : IO.read(file)
|
78
98
|
yaml = YAML::load(input)
|
79
|
-
return yaml[
|
99
|
+
return yaml[@tags_key] || []
|
80
100
|
rescue
|
81
101
|
return []
|
82
102
|
end
|
@@ -103,7 +123,7 @@ class JTag
|
|
103
123
|
if parts.length >= 2
|
104
124
|
begin
|
105
125
|
yaml = YAML::load(parts[1])
|
106
|
-
current_tags = yaml[
|
126
|
+
current_tags = yaml[@tags_key] || []
|
107
127
|
title = yaml["title"] || ""
|
108
128
|
rescue
|
109
129
|
current_tags = []
|
@@ -175,7 +195,7 @@ class JTag
|
|
175
195
|
begin
|
176
196
|
if File.exists?(file)
|
177
197
|
yaml, after = split_post(file)
|
178
|
-
yaml[
|
198
|
+
yaml[@tags_key] = tags
|
179
199
|
File.open(file,'w+') do |f|
|
180
200
|
f.puts yaml.to_yaml
|
181
201
|
f.puts "---"
|
@@ -190,5 +210,52 @@ class JTag
|
|
190
210
|
return false
|
191
211
|
end
|
192
212
|
end
|
193
|
-
end
|
194
213
|
|
214
|
+
private
|
215
|
+
|
216
|
+
def color(name)
|
217
|
+
color = {}
|
218
|
+
color['black'] = "\033[0;30m"
|
219
|
+
color['red'] = "\033[0;31m"
|
220
|
+
color['green'] = "\033[0;32m"
|
221
|
+
color['yellow'] = "\033[0;33m"
|
222
|
+
color['blue'] = "\033[0;34m"
|
223
|
+
color['magenta'] = "\033[0;35m"
|
224
|
+
color['cyan'] = "\033[0;36m"
|
225
|
+
color['white'] = "\033[0;37m"
|
226
|
+
color['bgblack'] = "\033[0;40m"
|
227
|
+
color['bgred'] = "\033[0;41m"
|
228
|
+
color['bggreen'] = "\033[0;42m"
|
229
|
+
color['bgyellow'] = "\033[0;43m"
|
230
|
+
color['bgblue'] = "\033[0;44m"
|
231
|
+
color['bgmagenta'] = "\033[0;45m"
|
232
|
+
color['bgcyan'] = "\033[0;46m"
|
233
|
+
color['bgwhite'] = "\033[0;47m"
|
234
|
+
color['boldblack'] = "\033[1;30m"
|
235
|
+
color['boldred'] = "\033[1;31m"
|
236
|
+
color['boldgreen'] = "\033[1;32m"
|
237
|
+
color['boldyellow'] = "\033[1;33m"
|
238
|
+
color['boldblue'] = "\033[1;34m"
|
239
|
+
color['boldmagenta'] = "\033[1;35m"
|
240
|
+
color['boldcyan'] = "\033[1;36m"
|
241
|
+
color['boldwhite'] = "\033[1;37m"
|
242
|
+
color['boldbgblack'] = "\033[1;40m"
|
243
|
+
color['boldbgred'] = "\033[1;41m"
|
244
|
+
color['boldbggreen'] = "\033[1;42m"
|
245
|
+
color['boldbgyellow'] = "\033[1;43m"
|
246
|
+
color['boldbgblue'] = "\033[1;44m"
|
247
|
+
color['boldbgmagenta'] = "\033[1;45m"
|
248
|
+
color['boldbgcyan'] = "\033[1;46m"
|
249
|
+
color['boldbgwhite'] = "\033[1;47m"
|
250
|
+
color['default'] = "\033[0;39m"
|
251
|
+
color['warning'] = color['yellow']
|
252
|
+
color['warningb'] = color['boldyellow']
|
253
|
+
color['success'] = color['green']
|
254
|
+
color['successb'] = color['boldgreen']
|
255
|
+
color['neutral'] = color['white']
|
256
|
+
color['neutralb'] = color['boldwhite']
|
257
|
+
color['info'] = color['cyan']
|
258
|
+
color['infob'] = color['boldcyan']
|
259
|
+
color[name]
|
260
|
+
end
|
261
|
+
end
|
data/lib/jtag/version.rb
CHANGED
metadata
CHANGED
@@ -1,97 +1,100 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jtag
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.15
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Brett Terpstra
|
9
|
-
autorequire:
|
8
|
+
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2021-05-14 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rake
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">="
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '0'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: rdoc
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - ">="
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - ">="
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: aruba
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - ">="
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: '0'
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - ">="
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: '0'
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: gli
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
|
-
- -
|
59
|
+
- - "~>"
|
68
60
|
- !ruby/object:Gem::Version
|
69
|
-
version: 2.
|
61
|
+
version: 2.20.0
|
70
62
|
type: :runtime
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
|
-
- -
|
66
|
+
- - "~>"
|
76
67
|
- !ruby/object:Gem::Version
|
77
|
-
version: 2.
|
68
|
+
version: 2.20.0
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: json
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
|
-
- -
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 2.2.0
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.2.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: plist
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
84
88
|
- !ruby/object:Gem::Version
|
85
89
|
version: '0'
|
86
90
|
type: :runtime
|
87
91
|
prerelease: false
|
88
92
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
93
|
requirements:
|
91
|
-
- -
|
94
|
+
- - ">="
|
92
95
|
- !ruby/object:Gem::Version
|
93
96
|
version: '0'
|
94
|
-
description:
|
97
|
+
description:
|
95
98
|
email: me@brettterpstra.com
|
96
99
|
executables:
|
97
100
|
- jtag
|
@@ -100,52 +103,43 @@ extra_rdoc_files:
|
|
100
103
|
- README.rdoc
|
101
104
|
- jtag.rdoc
|
102
105
|
files:
|
106
|
+
- README.rdoc
|
103
107
|
- bin/jtag
|
104
|
-
-
|
108
|
+
- jtag.rdoc
|
109
|
+
- lib/jtag.rb
|
105
110
|
- lib/jtag/config_files/blacklist.txt
|
106
111
|
- lib/jtag/config_files/config.yml
|
107
112
|
- lib/jtag/config_files/stopwords.txt
|
108
113
|
- lib/jtag/config_files/synonyms.yml
|
109
|
-
- lib/jtag/porter_stemming.rb
|
110
114
|
- lib/jtag/jekylltag.rb
|
115
|
+
- lib/jtag/porter_stemming.rb
|
111
116
|
- lib/jtag/string.rb
|
112
|
-
- lib/jtag.rb
|
113
|
-
- README.rdoc
|
114
|
-
- jtag.rdoc
|
117
|
+
- lib/jtag/version.rb
|
115
118
|
homepage: http://brettterpstra.com
|
116
119
|
licenses: []
|
117
|
-
|
120
|
+
metadata: {}
|
121
|
+
post_install_message:
|
118
122
|
rdoc_options:
|
119
|
-
- --title
|
123
|
+
- "--title"
|
120
124
|
- jtag
|
121
|
-
- --main
|
125
|
+
- "--main"
|
122
126
|
- README.rdoc
|
123
|
-
- -ri
|
124
127
|
require_paths:
|
125
128
|
- lib
|
126
129
|
- lib
|
127
130
|
required_ruby_version: !ruby/object:Gem::Requirement
|
128
|
-
none: false
|
129
131
|
requirements:
|
130
|
-
- -
|
132
|
+
- - ">="
|
131
133
|
- !ruby/object:Gem::Version
|
132
134
|
version: '0'
|
133
|
-
segments:
|
134
|
-
- 0
|
135
|
-
hash: -591621506323502236
|
136
135
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
|
-
none: false
|
138
136
|
requirements:
|
139
|
-
- -
|
137
|
+
- - ">="
|
140
138
|
- !ruby/object:Gem::Version
|
141
139
|
version: '0'
|
142
|
-
segments:
|
143
|
-
- 0
|
144
|
-
hash: -591621506323502236
|
145
140
|
requirements: []
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
specification_version: 3
|
141
|
+
rubygems_version: 3.2.16
|
142
|
+
signing_key:
|
143
|
+
specification_version: 4
|
150
144
|
summary: Auto-tagging and tagging tools for Jekyll
|
151
145
|
test_files: []
|