DirTagger 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/bin/dir_tagger +4 -0
  2. data/lib/dir_tagger.rb +257 -0
  3. metadata +50 -0
data/bin/dir_tagger ADDED
@@ -0,0 +1,4 @@
1
+ #! /usr/bin/env ruby
2
+ require_relative '../lib/dir_tagger.rb'
3
+
4
+ DirTagger::DirTaggerOperator.new ARGV
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: []