oktags 0.1.0 → 0.2.2

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 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