DirTagger 2.0.0
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/bin/dir_tagger +4 -0
- data/lib/dir_tagger.rb +257 -0
- metadata +50 -0
data/bin/dir_tagger
ADDED
data/lib/dir_tagger.rb
ADDED
@@ -0,0 +1,257 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'pathname'
|
4
|
+
require 'tempfile'
|
5
|
+
|
6
|
+
module DirTagger # :nodoc:
|
7
|
+
Profile_Name = '.tag_dir_profile'
|
8
|
+
class DirTagger
|
9
|
+
include Comparable
|
10
|
+
attr_accessor :tag, :dir, :children
|
11
|
+
def initialize(tag, dir, children = DirTaggers.new)
|
12
|
+
@tag = tag
|
13
|
+
@dir = dir
|
14
|
+
@children = children
|
15
|
+
end
|
16
|
+
|
17
|
+
def <=> (another_dir_tagger)
|
18
|
+
tag.length <=> another_dir_tagger.tag.length
|
19
|
+
end
|
20
|
+
|
21
|
+
def length
|
22
|
+
tag.length
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# == Test Data ==
|
27
|
+
# dts = DirTaggers.new
|
28
|
+
# dts.take_in DirTagger.new('first', 'Dir1')
|
29
|
+
# dts.take_in DirTagger.new('second', 'Dir2')
|
30
|
+
# dts.take_in DirTagger.new('third', 'Dir3')
|
31
|
+
# dts.take_in DirTagger.new('forth', 'Dir4'), ['first']
|
32
|
+
# dts.take_in DirTagger.new('fifth', 'Dir5'), %w(first forth)
|
33
|
+
class DirTaggers < Array
|
34
|
+
# Push a new TaggedDirs
|
35
|
+
def initialize
|
36
|
+
@empty = true
|
37
|
+
end
|
38
|
+
|
39
|
+
def take_in (dir_tagger, parent_tags = [])
|
40
|
+
if parent_tags.empty?
|
41
|
+
self << dir_tagger
|
42
|
+
else
|
43
|
+
searching_tag = parent_tags.shift
|
44
|
+
each { |dt|
|
45
|
+
if dt.tag == searching_tag
|
46
|
+
dt.children.take_in dir_tagger, parent_tags
|
47
|
+
break
|
48
|
+
end
|
49
|
+
}
|
50
|
+
end
|
51
|
+
@empty = false
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
def max_tag_length
|
56
|
+
@max_tag_length ||= sort.last.length
|
57
|
+
end
|
58
|
+
|
59
|
+
def empty?
|
60
|
+
@empty
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class DirTaggerOperator
|
65
|
+
attr_accessor :options, :profile, :dir_taggers
|
66
|
+
def initialize(argv) # :nodoc:
|
67
|
+
argv.push('-l') if argv.length.zero?
|
68
|
+
@options = OpenStruct.new(:actions => [], :parent_tags => [])
|
69
|
+
(OptionParser.new do |opts|
|
70
|
+
opts.banner = 'Usage: tagdir tag[,directory] [options]'
|
71
|
+
opts.separator ''
|
72
|
+
opts.separator 'SPECIFIC OPTIONS:'
|
73
|
+
|
74
|
+
opts.on('-a', '--add tag[,directory]', :REQUIRED, Array, 'Tag a directory, the defaualt directory is the current directory') do |tag, dir|
|
75
|
+
options.actions.push :new_tag
|
76
|
+
options.tag = tag
|
77
|
+
options.dir = dir.nil? ? Dir.pwd : dir
|
78
|
+
end
|
79
|
+
|
80
|
+
opts.on('-u', '--under tag[,tag2, ..]', Array, 'Operate tag within parent tags') do |tags|
|
81
|
+
options.parent_tags = tags # .split(',')
|
82
|
+
end
|
83
|
+
|
84
|
+
opts.on('-r', '--remove tag,[tag2, ..]', :REQUIRED, Array, 'Remove one or more tags') do |tags|
|
85
|
+
options.actions.push :remove_tag
|
86
|
+
options.tag_patterns = tags # .split(',')
|
87
|
+
end
|
88
|
+
|
89
|
+
# opts.on('-c', '--rename old_tag,new_tag', :REQUIRED, Array, 'Rename tag') do |old_tag, new_tag|
|
90
|
+
# options.actions.push :rename_tag
|
91
|
+
# options.old_tag = old_tag
|
92
|
+
# options.new_tag = new_tag
|
93
|
+
# end
|
94
|
+
|
95
|
+
opts.on('-l', '--list', 'List all the saved paths') do
|
96
|
+
options.actions.push :list_tags_and_dirs
|
97
|
+
end
|
98
|
+
|
99
|
+
# ToDo => Support listing all saved keys
|
100
|
+
# List all or specified tags
|
101
|
+
opts.on('-t', '--tags [pattern1, ..]', Array, '') do |pattern|
|
102
|
+
options.actions.push :list_tags
|
103
|
+
pattern = pattern.nil? ? '' : pattern
|
104
|
+
options.pattern = pattern
|
105
|
+
end
|
106
|
+
|
107
|
+
# List all or specified directories
|
108
|
+
opts.on('-d', '--dir [pattern1, ..]', Array, '') do |pattern|
|
109
|
+
options.actions.push :list_dirs
|
110
|
+
pattern = pattern.nil? ? '' : pattern
|
111
|
+
options.pattern = pattern
|
112
|
+
end
|
113
|
+
|
114
|
+
opts.on('-v', '--version', 'List current TagDir Version') do
|
115
|
+
puts '2.0.0'
|
116
|
+
exit
|
117
|
+
end
|
118
|
+
|
119
|
+
opts.on('-h', '--help', 'Display help message') do
|
120
|
+
puts opts
|
121
|
+
exit
|
122
|
+
end
|
123
|
+
|
124
|
+
# To Solve => Why options is empty when it is invoked in this block?
|
125
|
+
# if options.actions.empty?
|
126
|
+
# options.actions << :get_dir
|
127
|
+
# options.tags = argv
|
128
|
+
# end
|
129
|
+
end).parse(argv)
|
130
|
+
|
131
|
+
# Preparing for the running environment
|
132
|
+
@profile = Pathname.new(Dir.home).join(Profile_Name) # profile path
|
133
|
+
@dir_taggers = DirTaggers.new
|
134
|
+
# Run actions
|
135
|
+
if options.actions.empty?
|
136
|
+
options.actions << :get_dir
|
137
|
+
options.tags = argv
|
138
|
+
end
|
139
|
+
options.actions.each { |action| send action }
|
140
|
+
end
|
141
|
+
|
142
|
+
def new_tag
|
143
|
+
mode = profile.exist? ? 'a' : 'w'
|
144
|
+
profile.open(mode) do |f|
|
145
|
+
f << (options.parent_tags.empty? ? '' : "#{options.parent_tags.join(',')},") \
|
146
|
+
<< "#{options.tag};#{options.dir}\n"
|
147
|
+
end
|
148
|
+
puts "\e[32m Add Success"
|
149
|
+
end
|
150
|
+
|
151
|
+
def remove_tag
|
152
|
+
tmp_paths_profile = Tempfile.new(Profile_Name)
|
153
|
+
removed_tag = ''
|
154
|
+
profile.each_line do |l|
|
155
|
+
tags = tags_and_dir(l)[0]
|
156
|
+
if removed_tag.empty? && tag_match?(tags, options.tag_patterns, false)
|
157
|
+
removed_tag = tags.join(',')
|
158
|
+
next
|
159
|
+
end
|
160
|
+
next if !removed_tag.empty? && l.match(/^#{removed_tag}/)
|
161
|
+
tmp_paths_profile << l
|
162
|
+
end
|
163
|
+
FileUtils.mv(tmp_paths_profile.to_path, profile.to_path)
|
164
|
+
puts "\e[31m " + (removed_tag.empty? ? "Tagged Directory Not Existed" : "Remove Success")
|
165
|
+
end
|
166
|
+
|
167
|
+
# def rename_tag
|
168
|
+
# tmp_paths_profile = Tempfile.new(Profile_Name)
|
169
|
+
# profile.each_line do |line|
|
170
|
+
# if line.split(',').first.match(Regexp.new(options.old_key))
|
171
|
+
# tmp_paths_profile << "#{options.new_key},#{line.split(',')[1]}"
|
172
|
+
# else
|
173
|
+
# tmp_paths_profile << line
|
174
|
+
# end
|
175
|
+
# end
|
176
|
+
# FileUtils.mv(tmp_paths_profile.to_path, profile.to_path)
|
177
|
+
# puts "\e[32m Rename Success"
|
178
|
+
# end
|
179
|
+
|
180
|
+
def list_tags_and_dirs
|
181
|
+
puts 'All the Tagged Directories:'
|
182
|
+
tag_dir_printer saved_dir_taggers
|
183
|
+
end
|
184
|
+
|
185
|
+
# Get instance of DirTaggers, init
|
186
|
+
def saved_dir_taggers
|
187
|
+
unless profile.exist?
|
188
|
+
puts "\e[031m Not Any Directory Tagged"
|
189
|
+
exit
|
190
|
+
end
|
191
|
+
if dir_taggers.empty?
|
192
|
+
profile.each_line do |l|
|
193
|
+
tags, dir = tags_and_dir(l)
|
194
|
+
dir_taggers.take_in DirTagger.new(tags.pop, dir.first), tags
|
195
|
+
end
|
196
|
+
end
|
197
|
+
dir_taggers
|
198
|
+
end
|
199
|
+
|
200
|
+
def tag_dir_printer(dir_taggers, prefix = 0)
|
201
|
+
dir_taggers.each do |dt|
|
202
|
+
puts sprintf("\e[032m%#{dir_taggers.max_tag_length + prefix}s\e[0m %s", dt.tag, dt.dir)
|
203
|
+
tag_dir_printer dt.children, dir_taggers.max_tag_length + prefix
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# def list_tags
|
208
|
+
#
|
209
|
+
# end
|
210
|
+
|
211
|
+
# def list_dirs
|
212
|
+
#
|
213
|
+
# end
|
214
|
+
|
215
|
+
# def get_tag
|
216
|
+
# profile_parser(options.pattern, 0)
|
217
|
+
# end
|
218
|
+
|
219
|
+
def get_dir
|
220
|
+
puts profile_parser(options.tags, 1)
|
221
|
+
end
|
222
|
+
|
223
|
+
private
|
224
|
+
def profile_parser(tag_patterns, index)
|
225
|
+
tags_or_dir = ''
|
226
|
+
profile.each_line do |line|
|
227
|
+
tags, dir = tags_and_dir(line)
|
228
|
+
if tag_match?(tags, tag_patterns, tag_patterns.count == 1)
|
229
|
+
tags_or_dir = [tags, dir][index]
|
230
|
+
break
|
231
|
+
end
|
232
|
+
end
|
233
|
+
tags_or_dir
|
234
|
+
end
|
235
|
+
|
236
|
+
# Check if the nested tags match the patterns of tag
|
237
|
+
def tag_match?(tags, tag_patterns, last_only)
|
238
|
+
if last_only
|
239
|
+
tags.last.match(Regexp.new(tag_patterns.last))
|
240
|
+
else
|
241
|
+
return false if tags.count != tag_patterns.count
|
242
|
+
all_match = true
|
243
|
+
tags.each_with_index do |tag, i|
|
244
|
+
unless tag.match(Regexp.new(tag_patterns[i]))
|
245
|
+
all_match = false
|
246
|
+
break
|
247
|
+
end
|
248
|
+
end
|
249
|
+
all_match
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def tags_and_dir(line)
|
254
|
+
line.split(';').map { |s| s.split(',') }
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
metadata
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: DirTagger
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Van Hu
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-22 00:00:00.000000000Z
|
13
|
+
dependencies: []
|
14
|
+
description: ! "A gem saving some frequent used paths and keeping them at hand, both
|
15
|
+
in a very ease and comportable way. The concept is to give your directory a tag,
|
16
|
+
and then store it in '~/.tag_dir_profile'. After that, you can retrieve the path
|
17
|
+
of the directory by a shell command with the tag as parameter.\n https://github.com/bom-d-van/dir_tagger"
|
18
|
+
email: bom.d.van@gmail.com
|
19
|
+
executables:
|
20
|
+
- dir_tagger
|
21
|
+
extensions: []
|
22
|
+
extra_rdoc_files: []
|
23
|
+
files:
|
24
|
+
- lib/dir_tagger.rb
|
25
|
+
- bin/dir_tagger
|
26
|
+
homepage: https://github.com/bom-d-van/dir_tagger
|
27
|
+
licenses: []
|
28
|
+
post_install_message:
|
29
|
+
rdoc_options: []
|
30
|
+
require_paths:
|
31
|
+
- lib
|
32
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
requirements: []
|
45
|
+
rubyforge_project:
|
46
|
+
rubygems_version: 1.8.17
|
47
|
+
signing_key:
|
48
|
+
specification_version: 3
|
49
|
+
summary: ! '*nix system file system helper'
|
50
|
+
test_files: []
|