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.
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: []