oktags 0.1.0 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 68dace0200066373c4f27abc74ffb4fbb5faa9599b6a2771bf436d89ce92dcbe
4
- data.tar.gz: 1f50358bc643e20f55fa8d9f909f12e43600a44460cbb8b2c82dee6e3ce0c7e3
3
+ metadata.gz: 627114b53a234963a6e1547602f9bdabbd2e91814b6d7b07de8d2f07989170c4
4
+ data.tar.gz: 16fe1866c9793190c90af178b5125685b4afd4645cb2e43574c952466408bb5b
5
5
  SHA512:
6
- metadata.gz: b6213c7ff2043dcec1246a771b9919212098152672ab590fc89c3910094a940b984be2ca7b67acda67e78d21db54461036b378f6de33327f399cedb9216eb5c8
7
- data.tar.gz: 19e306cf0c524f9f67ca951606bbad2aed2342346b0c85b0c4cbba028eb47a8ccabf7375a42e4d0719c4db0595ed662ee8b362479b077d5421ba4bf7a60fa937
6
+ metadata.gz: d85747e3fd8ccad82fa328a853a3aea67e4ae6d2116474e34f61599fe535624f89ba8d540e296a847e652b5273bbcb60e95c340d236039ac4124a9d79b0bf983
7
+ data.tar.gz: 5d606c25adf29ace1025ce67a2287f4078775254c3dba57768dcdfc8e79a5390abdddd8976e3c4d6a37f45dd60e417271d9a3093a2db6d4dfbabe5812cc18530
@@ -5,7 +5,7 @@
5
5
  # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
6
  # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
7
 
8
- name: Ruby
8
+ name: CI
9
9
 
10
10
  on:
11
11
  push:
data/Gemfile CHANGED
@@ -2,7 +2,9 @@ source 'https://rubygems.org' do
2
2
  # Specify your gem's dependencies in oktags.gemspec
3
3
  gemspec
4
4
 
5
- gem "rake", "~> 12.0"
6
-
7
- gem 'rspec'
5
+ group :development, :test do
6
+ gem 'rake', '~> 12.0'
7
+ gem 'rspec'
8
+ gem 'byebug'
9
+ end
8
10
  end
@@ -1,11 +1,12 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- oktags (0.1.0)
4
+ oktags (0.2.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
+ byebug (11.1.3)
9
10
  diff-lcs (1.4.4)
10
11
  rake (12.3.2)
11
12
  rspec (3.9.0)
@@ -26,6 +27,7 @@ PLATFORMS
26
27
  ruby
27
28
 
28
29
  DEPENDENCIES
30
+ byebug!
29
31
  oktags!
30
32
  rake (~> 12.0)!
31
33
  rspec!
data/README.org CHANGED
@@ -7,6 +7,9 @@
7
7
  |___/
8
8
  #+end_example
9
9
 
10
+ #+html: <img src="https://github.com/200ok-ch/oktags/workflows/CI/badge.svg"/>
11
+ #+html: <a href="https://rubygems.org/gems/oktags"> <img src="https://badge.fury.io/rb/oktags.svg"/></a>
12
+
10
13
  * NAME
11
14
 
12
15
  =oktags= - manage tags on plain old files
@@ -15,52 +18,53 @@
15
18
 
16
19
  #+begin_example
17
20
  Usage: oktags [options]
18
- -l, --list [PATH] List file tags (optionally for PATH)
19
21
  -a, --add-tags TAGS FILE Add comma-separated TAGS to FILE
22
+ -d TAG FILE, Delete TAG from FILE
23
+ --delete-tag-from-file
20
24
  -i FILE, Auto-complete tags and add them to FILE
21
25
  --add-tags-interactively
26
+ -l, --list [PATH] List file tags (optional PATH)
22
27
  -r, --rename-tag OLD_TAG NEW_TAG Rename OLD_TAG to NEW_TAG(S) recursively for all files
23
- -d TAG FILE, Delete TAG from FILE
24
- --delete-tag-from-file
28
+ -s TAGS [PATH], Search files which include (comma-separated) tags recursively (optional PATH)
29
+ --search-files-with-tags
25
30
  #+end_example
26
31
 
27
32
  * DESCRIPTION
28
33
 
29
- =oktags= helps you organize your files by managing tags on them.
30
- It works by adding/removing tags at the end of the filename after a
31
- =--= qualifier. The implementation is OS-agnostic, so it should work
32
- on Linux, macOS and Windows.
34
+ =oktags= helps you organize your files by managing tags on them. It
35
+ works by adding/removing at the end of the filename. Given a file
36
+ =cat.jpg=, when adding the tags =tag1= and =tag2=, the filename will
37
+ become =cat--[tag1,tag2].jpg=. The implementation is OS-agnostic, so
38
+ it should work on Linux, macOS and Windows.
33
39
 
34
40
  * EXAMPLES
35
41
 
36
- Listing all tags in the current folder.
37
-
38
- #+begin_example
39
- $ touch foo
40
- $ touch bar.txt
41
- $ touch foobar--tag1,tag2.pdf
42
- $ touch baz--tag1.txt
43
- $ oktags -l
44
- tag1(2)
45
- tag2(1)
46
- #+end_example
47
-
48
- Listing all tags for a given path glob (assuming the same data set as above).
42
+ Add tags to a file. Tags are always unique.
49
43
 
50
44
  #+begin_example
51
- $ oktags -l '*txt'
52
- tag1(1)
45
+ $ touch foobar
46
+ $ oktags -a tag1 foobar
47
+ $ ls foobar*
48
+ foobar--[tag1]
49
+ $ oktags -a tag2 foobar--\[tag1\]
50
+ $ ls foobar*
51
+ foobar--[tag1,tag2]
52
+ $ oktags -a tag3,tag2 foobar--[tag1,tag2].pdf
53
+ $ ls foobar*
54
+ foobar--[tag1,tag2,tag3].pdf
53
55
  #+end_example
54
56
 
55
- Adding tags to a file. NB: Tags are always unique.
57
+ Delete a tag from a file.
56
58
 
57
59
  #+begin_example
58
- oktags -a tag3,tag2 foobar--tag1,tag2.pdf
59
- $ ls foobar*
60
- foobar--tag1,tag2,tag3.pdf
60
+ $ find . | grep business_card | head -n 1
61
+ ./archiv/Reto_Huber--[business_card,somedia,seo].pdf
62
+ $ oktags -d seo ./archiv/Reto_Huber--[business_card,somedia,seo].pdf
63
+ $ find . | grep business_card | head -n 1
64
+ ./archiv/Reto_Huber--[business_card,somedia].pdf
61
65
  #+end_example
62
66
 
63
- Interactively adding tags (with auto-completion through readline) to a file.
67
+ Interactively add tags (with auto-completion through readline) to a file.
64
68
 
65
69
  #+begin_example
66
70
  $ oktags -i foo
@@ -68,30 +72,50 @@ Interactively adding tags (with auto-completion through readline) to a file.
68
72
  tag1 tag2 tag3
69
73
  > tag2, new tag
70
74
  $ ls foo* | grep new
71
- foo--new tag,tag2
75
+ foo--[new_tag,tag2]
76
+ #+end_example
77
+
78
+ List all tags in the current folder.
79
+
80
+ #+begin_example
81
+ $ touch foo
82
+ $ touch bar.txt
83
+ $ touch foobar--[tag1,tag2].pdf
84
+ $ touch baz--[tag1].txt
85
+ $ oktags -l
86
+ tag1(2)
87
+ tag2(1)
88
+ #+end_example
89
+
90
+ List all tags for a given path glob (assuming the same data set as above).
91
+
92
+ #+begin_example
93
+ $ oktags -l '*txt'
94
+ tag1(1)
72
95
  #+end_example
73
96
 
74
- Renaming tags.
97
+ Rename tag.
75
98
 
76
99
  #+begin_example
77
100
  $ oktags -l
78
101
  200ok_expense(8)
79
102
  business_card(4)
80
- $ oktags -r 200ok_expense "200ok,expense"
103
+ $ oktags -r 200ok_expense 200ok,expense
81
104
  $ oktags -l
82
105
  expense(8)
83
106
  200ok(8)
84
107
  business_card(4)
85
108
  #+end_example
86
109
 
87
- Remove a tag from a file.
110
+ Search files with tags.
88
111
 
89
112
  #+begin_example
90
- $ find . | grep business_card | head -n 1
91
- ./archiv/Cyrill_Schwitter--business_card,somedia,seo.pdf
92
- $ oktags -d seo ./archiv/Cyrill_Schwitter--business_card,somedia,seo.pdf
93
- $ find . | grep business_card | head -n 1
94
- ./archiv/Cyrill_Schwitter--business_card,somedia.pdf
113
+ $ oktags -s somedia,seo,business_card
114
+ archiv/Reto_Huber--[business_card,seo,somedia].pdf
115
+ archiv/Reto_Huber--[business_card,seo,somedia].txt
116
+ $ oktags -s business_card '**/*pdf'
117
+ archiv/Reto_Huber--[business_card,seo,somedia].pdf
118
+ archiv/Stefan_Schmidt--[business_card,lawoon].pdf
95
119
  #+end_example
96
120
 
97
121
  * INSTALLATION
@@ -111,28 +135,21 @@ You can also run =bin/console= for an interactive prompt that will
111
135
  allow you to experiment.
112
136
 
113
137
  To install this gem onto your local machine, run =bundle exec rake
114
- install=. To release a new version, update the version number in
115
- =version.rb=, and then run =bundle exec rake release=, which will
138
+ install=. To publish a new version, update the version number in
139
+ =version.rb=, and then run =bundle exec rake publish=, which will
116
140
  create a git tag for the version, push git commits and tags, and push
117
141
  the =.gem= file to [[https://rubygems.org][rubygems.org]].
118
142
 
119
143
  * TESTS
120
144
 
121
- Tests are implemented with [[https://rspec.info/][RSpec]] and can be run like this:
122
-
123
- #+begin_src shell
124
- $ rpsec spec
125
- .....
126
-
127
- Finished in 0.00351 seconds (files took 0.06834 seconds to load)
128
- 5 examples, 0 failures
129
- #+end_src
145
+ Tests are implemented with [[https://rspec.info/][RSpec]] and can be run with =bundle exec
146
+ rspec spec=.
130
147
 
131
148
  * NOTES
132
149
 
133
150
  Software systems come and go. It is easy to lose important data in
134
- (proprietary) legacy systems. Plain old files are boring and therefore
135
- are here to stay; at least they [[https://en.wikipedia.org/wiki/Computer_file#Storage][have been around since 1961]].
151
+ (proprietary) legacy systems. Plain old files are boring and are
152
+ therefore here to stay; at least they [[https://en.wikipedia.org/wiki/Computer_file#Storage][have been around since 1961]].
136
153
  Additional benefits of using plain old files are:
137
154
 
138
155
  - They are (mostly) platform independent.
@@ -143,14 +160,14 @@ Additional benefits of using plain old files are:
143
160
  - They can be transported independently from the software that captured/created them.
144
161
  - They are not proprietary.
145
162
 
146
- =oktags= is decidedly built to be just as boring as plain old
147
- files. It's written in a language that's been proven for shell scripts
148
- ([[https://www.ruby-lang.org/en/][Ruby]]) rather than using something more 'cool' like Clojure (with
149
- [[https://github.com/borkdude/babashka][babashka]] or [[https://github.com/anmonteiro/lumo][lumo]]). It also only uses Ruby primitives and has
150
- dependencies (apart from the test framework). =oktags= is
151
- therefore boring and here to stay. The idea is to tag your files once
152
- and for all, so you don't loose your important data in something that
153
- will become an unsupported legacy system at some point.
163
+ =oktags= is decidedly built to be just as boring as plain old files.
164
+ It's written in a language that's been proven for shell scripts ([[https://www.ruby-lang.org/en/][Ruby]])
165
+ rather than using something more 'cool'/'interesting'. It also only
166
+ uses Ruby built-ins and has no dependencies when run as a CLI or
167
+ library. =oktags= is therefore boring and here to stay. The idea is to
168
+ tag your files once and for all, so you will not loose your important
169
+ data in something that will become an unsupported legacy system at
170
+ some point.
154
171
 
155
172
  At [[https://200ok.ch/][200ok]], we develop various Free Software projects that work on plain
156
173
  old files:
data/Rakefile CHANGED
@@ -1,23 +1,23 @@
1
1
  require './lib/oktags'
2
2
  require './lib/ok/version'
3
3
 
4
- GEM_NAME = "oktags"
4
+ GEM_NAME = 'oktags'
5
5
  GEM_VERSION = OK::Tags::VERSION
6
6
 
7
- task :default => :build
7
+ task default: :build
8
8
 
9
9
  task :build do
10
- system "gem build " + GEM_NAME + ".gemspec"
10
+ system 'gem build ' + GEM_NAME + '.gemspec'
11
11
  end
12
12
 
13
- task :install => :build do
14
- system "gem install " + GEM_NAME + "-" + GEM_VERSION + ".gem"
13
+ task install: :build do
14
+ system 'gem install ' + GEM_NAME + '-' + GEM_VERSION + '.gem'
15
15
  end
16
16
 
17
- task :publish => :build do
18
- system 'gem push ' + GEM_NAME + "-" + GEM_VERSION + ".gem"
17
+ task publish: :build do
18
+ system 'gem push ' + GEM_NAME + '-' + GEM_VERSION + '.gem'
19
19
  end
20
20
 
21
21
  task :clean do
22
- system "rm *.gem"
22
+ system 'rm *.gem'
23
23
  end
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "bundler/setup"
4
- require "oktags"
3
+ require 'bundler/setup'
4
+ require 'oktags'
5
5
 
6
6
  # You can add fixtures and/or initialization code here to make experimenting
7
7
  # with your gem easier. You can also use a different console, if you like.
@@ -10,5 +10,5 @@ require "oktags"
10
10
  # require "pry"
11
11
  # Pry.start
12
12
 
13
- require "irb"
13
+ require 'irb'
14
14
  IRB.start(__FILE__)
data/bin/oktags CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'oktags'
4
- OK::Tags::main
3
+ require File.expand_path(File.join(%w[.. .. lib ok tags]), __FILE__)
4
+ OK::Tags.main
@@ -0,0 +1,15 @@
1
+ class Hash
2
+ # like invert but not lossy. possibly a good blog post.
3
+ def safe_invert
4
+ inject({}) do |acc, (k, v)|
5
+ if v.is_a? Array
6
+ v.each do |vx|
7
+ acc[vx] = acc[vx].nil? ? k : [acc[vx], k].flatten
8
+ end
9
+ else
10
+ acc[v] = acc[v].nil? ? k : [acc[v], k].flatten
11
+ end
12
+ acc
13
+ end
14
+ end
15
+ end
@@ -2,41 +2,72 @@
2
2
  # coding: utf-8
3
3
 
4
4
  require 'optparse'
5
+ require 'set'
5
6
  require 'readline'
6
7
  require 'fileutils'
8
+ require File.expand_path(File.join(%w[.. .. hash]), __FILE__)
7
9
 
8
10
  module OK
9
11
  module Tags
10
12
  class Error < StandardError; end
11
13
  extend self
12
14
 
13
- def find_tags_for(path)
14
- tags = []
15
- Dir.glob(path).each do |file|
16
- file = File.basename(file, ".*")
17
- file_tags = file.split('--')[1]&.split(',')&.map(&:strip)&.map(&:downcase)
18
- tags << file_tags if file_tags
15
+ # oktags uses --[] as the place to save tags. [] does have special
16
+ # meaning for Ruby Dir.glob, though. Hence, it's escaped.
17
+ def escape_glob(s)
18
+ s&.gsub(/[\[\]]/) { |x| "\\" + x }
19
+ end
20
+
21
+ def search_files_with_tags(path = '**/*')
22
+ tagged_files = Hash.new { |h, k| h[k] = [] }
23
+
24
+ Dir.glob(escape_glob(path)).each do |file|
25
+ basename = File.basename(file, '.*')
26
+ file_tags =
27
+ basename.match(/--\[(.*)\]/)&.to_a&.at(1)&.split(',')&.map(&:strip)
28
+ &.map(&:downcase)
29
+ file_tags.each { |t| tagged_files[t] << file } if file_tags
19
30
  end
31
+ tagged_files
32
+ end
33
+
34
+ def list_files_with_tags(tags, path = '**/*')
35
+ # TODO: Refactor reused code
36
+ tags = tags.split(',')&.map(&:strip)&.map(&:downcase)
37
+
38
+ tagged_files = search_files_with_tags(path)
39
+ files =
40
+ tagged_files.safe_invert.filter do |files, file_tags|
41
+ file_tags = [file_tags] if file_tags.is_a? String
42
+ tags.to_set.subset?(file_tags.to_set)
43
+ end&.keys&.flatten&.sort
44
+
45
+ puts files
46
+ files
47
+ end
20
48
 
21
- tags = tags.flatten.compact
49
+ def find_tags_for(path = '**/*')
50
+ tagged_files =
51
+ path ? search_files_with_tags(path) : search_files_with_tags
52
+ # return an array with redundant tags
53
+ tagged_files.map { |k, v| Array.new(v.count, k) }.flatten.sort
22
54
  end
23
55
 
24
56
  def count_tags(tags)
25
- tags.inject({}) { |acc, tag|
57
+ tags.inject({}) do |acc, tag|
26
58
  acc[tag] = acc[tag].to_i + 1
27
59
  acc
28
- }
60
+ end
29
61
  end
30
62
 
31
- def list_pretty_tags(path = nil)
32
- tags = find_tags_for(path || '**/*')
63
+ def list_pretty_tags(path = '**/*')
64
+ tags = find_tags_for(path)
33
65
  counts = count_tags(tags)
34
66
 
35
- pretty_counts = counts.sort_by { |tag, count| count }
36
- .reverse
37
- .map do |tag, count|
38
- "#{tag}(#{count})"
39
- end
67
+ pretty_counts =
68
+ counts.sort_by { |tag, count| count }.reverse.map do |tag, count|
69
+ "#{tag}(#{count})"
70
+ end
40
71
 
41
72
  puts pretty_counts
42
73
  end
@@ -44,58 +75,82 @@ module OK
44
75
  def filename_with_tags(file, tags)
45
76
  dirname = File.dirname(file)
46
77
  ext = File.extname(file)
47
- basename = File.basename(file, ".*").split('--')[0]
48
- File.join(dirname, "#{basename}--#{tags.join(',')}#{ext}")
78
+ basename = File.basename(file, '.*')
79
+ tag_part = basename.match(/--\[(.*)\]/)&.to_a&.at(0)
80
+ basename = basename.gsub(tag_part, '') if tag_part
81
+ File.join(dirname, "#{basename}--[#{tags.join(',')}]#{ext}")
49
82
  end
50
83
 
51
84
  def add_tags_to_file(new_tags, file)
52
- (puts "Needs a FILE input; i.e. `-a tag filename`"; exit) unless file
85
+ unless file
86
+ (
87
+ puts 'Needs a FILE input; i.e. `-a tag filename`'
88
+ exit
89
+ )
90
+ end
53
91
 
54
92
  tags = find_tags_for(file)
55
- tags << new_tags.split(',')&.map(&:strip)&.map(&:downcase)
93
+ tags <<
94
+ new_tags.split(',')&.map(&:strip)&.map(&:downcase)&.map do |t|
95
+ # Replace spaces in tags with underscores, because spaces in
96
+ # filenames can cause all kinds of issues depending on what
97
+ # tools are used on the filenames. The less requirements for
98
+ # escaping filenames, the better.
99
+ t.gsub(' ', '_')
100
+ end
101
+
56
102
  tags = tags.flatten.uniq.sort
57
103
 
58
104
  new_filename = filename_with_tags(file, tags)
59
- if file != new_filename
60
- FileUtils.mv(file, new_filename)
61
- end
105
+ FileUtils.mv(file, new_filename) if file != new_filename
62
106
 
63
107
  new_filename
64
108
  end
65
109
 
66
- def read_and_add_tags_for(file, tags_path = nil)
67
- (puts "File '#{file}' does not exist."; exit 1) unless File.exist?(file)
68
-
69
- tags = find_tags_for(tags_path || '**/*')
70
- Readline.completion_proc = proc do |input|
71
- tags.select { |tag| tag.start_with?(input) }
110
+ def read_and_add_tags_for(file, tags_path = '**/*')
111
+ unless File.exist?(file)
112
+ (
113
+ puts "File '#{file}' does not exist."
114
+ exit 1
115
+ )
72
116
  end
73
117
 
74
- puts "Add new tags:"
75
- new_tags = Readline.readline("> ", false)
118
+ tags = find_tags_for(tags_path)
119
+ Readline.completion_proc =
120
+ proc { |input| tags.select { |tag| tag.start_with?(input) } }
121
+
122
+ puts 'Add new tags:'
123
+ new_tags = Readline.readline('> ', false)
76
124
  new_filename = add_tags_to_file(new_tags, file)
77
125
  [new_tags, new_filename]
78
126
  end
79
127
 
80
128
  def delete_tag_from_file(tag, file)
81
- (puts "Needs a FILE input; i.e. `-d tag1 filename`"; exit) unless file
129
+ unless file
130
+ (
131
+ puts 'Needs a FILE input; i.e. `-d tag1 filename`'
132
+ exit
133
+ )
134
+ end
82
135
 
83
136
  tags = find_tags_for(file)
84
137
  tags = tags.reject { |t| t == tag }
85
138
 
86
139
  new_filename = filename_with_tags(file, tags)
87
- if file != new_filename
88
- FileUtils.mv(file, new_filename)
89
- end
140
+ FileUtils.mv(file, new_filename) if file != new_filename
90
141
 
91
142
  new_filename
92
143
  end
93
144
 
94
-
95
145
  def rename_tag(path, old_tag, new_tag)
96
- (puts "Needs a NEW_TAG input; i.e. `-r old_tag new_tag`"; exit) unless new_tag
146
+ unless new_tag
147
+ (
148
+ puts 'Needs a NEW_TAG input; i.e. `-r old_tag new_tag`'
149
+ exit
150
+ )
151
+ end
97
152
 
98
- Dir.glob("#{path}/**/*--*#{old_tag}*").each do |file|
153
+ Dir.glob("#{path}/**/*--\\[*#{old_tag}*\\]*").each do |file|
99
154
  file = add_tags_to_file(new_tag, file)
100
155
  delete_tag_from_file(old_tag, file)
101
156
  end
@@ -104,28 +159,61 @@ module OK
104
159
  def main
105
160
  OptionParser.new do |opts|
106
161
  opts.banner = 'Usage: oktags [options]'
107
- opts.on('-l', "--list [PATH]", 'List file tags (optionally for PATH)') do |path|
108
- list_pretty_tags(path)
162
+ opts.on(
163
+ '-a',
164
+ '--add-tags TAGS FILE',
165
+ 'Add comma-separated TAGS to FILE'
166
+ ) do |tags|
167
+ add_tags_to_file(tags, ARGV[0])
109
168
  exit
110
169
  end
111
- opts.on('-a', '--add-tags TAGS FILE', 'Add comma-separated TAGS to FILE') do |tags|
112
- add_tags_to_file(tags, ARGV[0])
170
+ opts.on(
171
+ '-d',
172
+ '--delete-tag-from-file TAG FILE',
173
+ 'Delete TAG from FILE'
174
+ ) do |tag|
175
+ delete_tag_from_file(tag, ARGV[0])
113
176
  exit
114
177
  end
115
- opts.on('-i', '--add-tags-interactively FILE', 'Auto-complete tags and add them to FILE') do |file|
178
+ opts.on(
179
+ '-i',
180
+ '--add-tags-interactively FILE',
181
+ 'Auto-complete tags and add them to FILE'
182
+ ) do |file|
116
183
  read_and_add_tags_for(file)
117
184
  exit
118
185
  end
119
- opts.on('-r', '--rename-tag OLD_TAG NEW_TAG', 'Rename OLD_TAG to NEW_TAG(S) recursively for all files') do |old_tag|
186
+ opts.on(
187
+ '-l',
188
+ '--list [PATH]',
189
+ 'List file tags recursively (at optional PATH)'
190
+ ) do |path|
191
+ path ? list_pretty_tags(path) : list_pretty_tags
192
+ exit
193
+ end
194
+ opts.on(
195
+ '-r',
196
+ '--rename-tag OLD_TAG NEW_TAG',
197
+ 'Rename OLD_TAG to NEW_TAG(S) recursively for all files'
198
+ ) do |old_tag|
120
199
  rename_tag('.', old_tag, ARGV[0])
121
200
  exit
122
201
  end
123
- opts.on('-d', '--delete-tag-from-file TAG FILE', 'Delete TAG from FILE') do |tag|
124
- delete_tag_from_file(tag, ARGV[0])
202
+ opts.on(
203
+ '-s',
204
+ '--search-files-with-tags TAGS [PATH]',
205
+ 'Search files which include (comma-separated) TAGS recursively (at optional PATH)'
206
+ ) do |tags|
207
+ if ARGV[0]
208
+ list_files_with_tags(tags, ARGV[0])
209
+ else
210
+ list_files_with_tags(tags)
211
+ end
125
212
  exit
126
213
  end
127
214
  end.parse!
128
-
129
215
  end
130
216
  end
131
217
  end
218
+
219
+ OK::Tags.main if $0 == __FILE__
@@ -1,5 +1,5 @@
1
1
  module OK
2
2
  module Tags
3
- VERSION = '0.1.0'
3
+ VERSION = '0.2.2'
4
4
  end
5
5
  end
@@ -1 +1 @@
1
- require File.expand_path(File.join(%w(.. ok tags)), __FILE__)
1
+ require File.expand_path(File.join(%w[.. ok tags]), __FILE__)
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
8
8
  spec.licenses = "AGPL-3.0-or-later"
9
9
 
10
10
  spec.summary = %q{Manage tags on plain old files.}
11
- spec.description = %q{oktags helps you organize your files by managing tags on them. It works by adding/removing tags at the end of the filename after a -- qualifier. The implementation is OS-agnostic, so it should work on Linux, macOS and Windows.}
11
+ spec.description = %q{oktags helps you organize your files by managing tags on them. It works by adding/removing at the end of the filename. Given a file 'cat.jpg', when adding the tags 'tag1' and 'tag2', the filename will become 'cat--[tag1,tag2].jpg'. The implementation is OS-agnostic, so it should work on Linux, macOS and Windows. }
12
12
  spec.homepage = "https://200ok.ch"
13
13
  spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
14
14
 
metadata CHANGED
@@ -1,18 +1,19 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oktags
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alain M. Lafon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-15 00:00:00.000000000 Z
11
+ date: 2020-10-19 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: oktags helps you organize your files by managing tags on them. It works
14
- by adding/removing tags at the end of the filename after a -- qualifier. The implementation
15
- is OS-agnostic, so it should work on Linux, macOS and Windows.
13
+ description: 'oktags helps you organize your files by managing tags on them. It works
14
+ by adding/removing at the end of the filename. Given a file ''cat.jpg'', when adding
15
+ the tags ''tag1'' and ''tag2'', the filename will become ''cat--[tag1,tag2].jpg''.
16
+ The implementation is OS-agnostic, so it should work on Linux, macOS and Windows. '
16
17
  email:
17
18
  - info@200ok.ch
18
19
  executables:
@@ -20,7 +21,7 @@ executables:
20
21
  extensions: []
21
22
  extra_rdoc_files: []
22
23
  files:
23
- - ".github/workflows/ruby.yml"
24
+ - ".github/workflows/ci.yml"
24
25
  - ".gitignore"
25
26
  - ".rspec"
26
27
  - ".ruby-version"
@@ -32,6 +33,7 @@ files:
32
33
  - bin/console
33
34
  - bin/oktags
34
35
  - bin/setup
36
+ - lib/hash.rb
35
37
  - lib/ok/tags.rb
36
38
  - lib/ok/version.rb
37
39
  - lib/oktags.rb