tagmv 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8f1e38a10e9ca3a7369ab50f4509529016fd430a
4
+ data.tar.gz: 4beb2cf52b95d5f11eda2277a91ad176d759ce23
5
+ SHA512:
6
+ metadata.gz: cd49965ab7495f1eec74d4fce995f50306f8a062b861b4e99f2efeddace1efcf71fbc77cfeb8163b9cc485c08b89a465b465426ae02a0764eb5f97fb316fefee
7
+ data.tar.gz: e29488194f1d0ea19666509ca25e6daa9006068baad3852d546f1a1ec5de187050ce73af94eb05936c8b82b06408b0cb62045d7c3009e90f8d2a87fb77e9a294
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.4
4
+ before_install: gem install bundler -v 1.11.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in tagmv.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # Tagmv
2
+
3
+ File tagging by moving files into tag-based directories.
4
+
5
+ The directories that represent tags are organized hierarchically (either by # of items that have the tag or some other method).
6
+
7
+ - Organizes using the plain file system
8
+ - Extremely flexible (no tag limit, no tag naming restrictions, hierarchical tags, no file naming restrictions, can tag all files and directories).
9
+ - Transparent to other applications, since it works directly with the file system.
10
+
11
+ ## Installation
12
+
13
+ $ gem install tagmv
14
+
15
+ ## Usage
16
+
17
+ $ tag <files/directories> -t <tags>
18
+
19
+ ## Development
20
+
21
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
22
+
23
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
24
+
25
+ ## Contributing
26
+
27
+ Bug reports and pull requests are welcome on GitHub at https://github.com/foucist/tagmv.
28
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :spec
data/bin/tagmv ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
4
+
5
+ require 'tagmv'
6
+
7
+ $:.unshift File.expand_path('./lib')
8
+ require 'tagmv/command_line'
9
+ require 'tagmv/runner'
10
+
11
+ Tagmv::Runner.run
@@ -0,0 +1,54 @@
1
+ require 'choice'
2
+
3
+ module Tagmv
4
+ module CommandLine
5
+ extend self
6
+
7
+ Choice.options do
8
+ header "\033[1m\033[32mtagmv\033[0m\033[0m: A Directory-based Tagging Organizer"
9
+ header ""
10
+ header "Options:"
11
+
12
+ footer ""
13
+ footer "tagmv by James Robey (http://jamesrobey.com/tagmv/)"
14
+
15
+ option :tags, :required => true do
16
+ short '-t'
17
+ long '--tags *tags'
18
+ desc 'The hostname or ip of the host to bind to (default 127.0.0.1)'
19
+ end
20
+ end
21
+
22
+ def parse
23
+ return Choice.help if Choice.rest.empty?
24
+
25
+ {files: Choice.rest, tags: Choice.choices[:tags]}
26
+ end
27
+ end
28
+ end
29
+
30
+ #module Tagmv
31
+ # class CommandLine
32
+ # def self.parse
33
+ # Choice.options do
34
+ # header "\033[1m\033[32mtagmv\033[0m\033[0m: A Directory-based Tagging Organizer"
35
+ # header ""
36
+ # header "Options:"
37
+ #
38
+ # footer ""
39
+ # footer "tagmv by James Robey (http://jamesrobey.com/tagmv/)"
40
+ #
41
+ # option :tags, :required => true do
42
+ # short '-t'
43
+ # long '--tags *tags'
44
+ # desc 'The hostname or ip of the host to bind to (default 127.0.0.1)'
45
+ # end
46
+ # end
47
+ #
48
+ # return Choice.help if Choice.rest.empty?
49
+ #
50
+ # {files: Choice.rest, tags: Choice.choices[:tags]}
51
+ # end
52
+ # end
53
+ #end
54
+
@@ -0,0 +1,27 @@
1
+ require 'yaml'
2
+
3
+ module Tagmv
4
+ class Config
5
+ def initialize(options = {})
6
+ @path = options[:path] || File.expand_path("~/.tagmv.yml")
7
+ end
8
+
9
+ def defaults
10
+ {top_level_tags: ["blog", "media"]}
11
+ end
12
+
13
+ def load
14
+ if File.file?(@path)
15
+ YAML.load(File.open(@path).read)
16
+ else
17
+ config = defaults
18
+ save(config)
19
+ config
20
+ end
21
+ end
22
+
23
+ def save(config)
24
+ File.open(@path, 'w') { |f| f.write(config.to_yaml) }
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,9 @@
1
+ module Tagmv
2
+ class Entry
3
+ attr_accessor :tags, :files
4
+ def initialize(opts={})
5
+ @tags = opts[:tags]
6
+ @files = opts[:files]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,48 @@
1
+ require 'fileutils'
2
+
3
+ module Tagmv
4
+ class Filesystem
5
+ @root = File.expand_path('~/t')
6
+ class << self
7
+ attr_accessor :root
8
+ end
9
+
10
+ attr_reader :tags, :files, :tag_order, :top_level_tags
11
+ def initialize(opts={})
12
+ @tags = opts[:tags].map {|t| scrub_tag(t) }
13
+ @files = opts[:files].map {|f| File.expand_path(f) }.select {|f| File.exist?(f) }
14
+ @tag_order = opts[:tag_order]
15
+ @top_level_tags = opts[:top_level_tags]
16
+ end
17
+
18
+ def scrub_tag(tag)
19
+ # only keep legit file characters & remove trailing periods
20
+ tag.gsub(/[^0-9A-Za-z\.\-\_]|[\.]+$/, '')
21
+ end
22
+
23
+ def tag_order
24
+ top_level_tags | @tag_order
25
+ end
26
+
27
+ def tag_dirs
28
+ (tag_order & tags).map {|x| x.gsub(/$/, '.') }
29
+ end
30
+
31
+ def target_dir
32
+ File.join(Filesystem.root, *tag_dirs)
33
+ end
34
+
35
+ def prepare_dir
36
+ FileUtils.mkdir_p(target_dir)
37
+ end
38
+
39
+ def move_files
40
+ FileUtils.mv(files, target_dir)
41
+ rescue ArgumentError
42
+ end
43
+
44
+ def transfer
45
+ prepare_dir && move_files
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,27 @@
1
+ module Tagmv
2
+ class PrunePath
3
+ attr_reader :path
4
+ def initialize(path)
5
+ @path = path
6
+ end
7
+
8
+ def tag_dir?
9
+ path =~ /\.$/ && path !~ Tagmv::Tree.false_tag_regex
10
+ end
11
+
12
+ def empty_dir?
13
+ FileTest.directory?(path) && Dir.entries(path) == ['.', '..']
14
+ end
15
+
16
+ def rmdir
17
+ Dir.rmdir(path) if tag_dir? && empty_dir?
18
+ end
19
+
20
+ def self.prune_tag_dirs
21
+ Find.find(Tagmv::Filesystem.root).reverse_each do |path|
22
+ Tagmv::PrunePath.new(path).rmdir
23
+ end
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,28 @@
1
+ module Tagmv
2
+ module Runner
3
+ extend self
4
+
5
+ def tree
6
+ @tree ||= Tagmv::Tree.scan_tree_entries
7
+ end
8
+
9
+ def update_tree
10
+ opts = Tagmv::CommandLine.parse
11
+ tree.with(opts)
12
+ end
13
+
14
+ def move_files
15
+ tree.entries.each do |entry|
16
+ tfs = Tagmv::Filesystem.new(tags: entry.tags, files: entry.files, tag_order: tree.tag_order, top_level_tags: @opts[:top_level_tags])
17
+ tfs.transfer
18
+ end
19
+ end
20
+
21
+ def run
22
+ @opts = Tagmv::Config.new.load
23
+ update_tree
24
+ move_files
25
+ Tagmv::PrunePath.prune_tag_dirs
26
+ end
27
+ end
28
+ end
data/lib/tagmv/tree.rb ADDED
@@ -0,0 +1,77 @@
1
+ require 'find'
2
+
3
+ module Tagmv
4
+ class Tree
5
+ attr_accessor :entries
6
+ def initialize(entries = [])
7
+ @entries = entries
8
+ end
9
+
10
+ def with(opts)
11
+ entries << Entry.new(opts)
12
+ end
13
+
14
+ def tag_counts
15
+ entries.map {|x| x.tags }.flatten.each_with_object(Hash.new(0)) { |word,counts| counts[word] += 1 }
16
+ end
17
+
18
+ def tag_order
19
+ tag_counts.to_a.sort_by{|x| [-x.last, x.first]}.map {|x| x.first }
20
+ end
21
+
22
+
23
+ def self.false_tag_regex
24
+ # detect when there's a false tag i.e. tag2. in path/to/tag1./not_a_tag/tag2./
25
+ /\/.+\.\/[^.]+\/.+\./
26
+ end
27
+ def self.tags_in_path_regex
28
+ /\/\K.+?(?=\.\/)/
29
+ end
30
+
31
+ def self.path_has_file_regex
32
+ /#{tags_in_path_regex}.*[^\.]$/
33
+ end
34
+
35
+ def self.tags(file)
36
+ raise StandardError.new('Invalid file path given') unless file[/^#{Filesystem.root}/]
37
+ file[Filesystem.root.length..-1].scan(tags_in_path_regex).reject {|x| x =~ /\//}
38
+ end
39
+
40
+ def self.empty_dirs
41
+ files = Find.find(Filesystem.root).select {|x| x =~ path_has_file_regex }
42
+ tree = Tree.new
43
+ files.map do |file|
44
+ next if file =~ false_tag_regex
45
+ tree.with(files: [file], tags: tags(file))
46
+ end
47
+ tree
48
+ end
49
+
50
+ def self.scan_tree_entries
51
+ files = Find.find(Filesystem.root).select {|x| x =~ path_has_file_regex }
52
+ tree = Tree.new
53
+ files.map do |file|
54
+ next if file =~ /\/.+\.\/[^.]+\/.+\./ # break when /dev./oh/blah./foo
55
+ tree.with(files: [file], tags: tags(file))
56
+ end
57
+ tree
58
+ end
59
+
60
+ # only gets existing tree, doesn't build an accurate tree based on all the tag counts etc..
61
+ # Find.find('.').select {|x| x =~ /([^\/]+\/)*([^\/]+\/)*\.\/.*/}
62
+ # {"dev."=>{"book."=>{"javascript."=>{"Secrets_of_the_Javascript_Ninja.pdf"=>{}}, "ruby."=>{"rails_antipatterns.pdf"=>{}}}, "ruby."=>{"oh"=>{}, "tagmv"=>{}}}}
63
+ def self.scan_tree_hash
64
+ Dir.chdir(Filesystem.root)
65
+ Dir["**/**./*"].inject({}) do |hash,path|
66
+ tree = hash
67
+ path.split("/").each do |n|
68
+ tree[n] ||= {}
69
+ tree = tree[n]
70
+ break if n[-1] != "."
71
+ end
72
+ hash
73
+ end
74
+ end
75
+ end
76
+
77
+ end
@@ -0,0 +1,3 @@
1
+ module Tagmv
2
+ VERSION = "0.0.1"
3
+ end
data/lib/tagmv.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'tagmv/version'
2
+
3
+ require 'tagmv/config'
4
+ require 'tagmv/entry'
5
+ require 'tagmv/filesystem'
6
+ require 'tagmv/prune_path'
7
+ require 'tagmv/tree'
data/tagmv.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'tagmv/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "tagmv"
8
+ spec.version = Tagmv::VERSION
9
+ spec.authors = ["James Robey"]
10
+ spec.email = ["james.robey+tagmv@gmail.com"]
11
+ spec.summary = %q{Tag your files by moving them into a tree-like tag structure}
12
+ spec.description = %q{Moves your files into directories that represent tags, these tags are kept organized as a hierarchy according to tag counts}
13
+ spec.homepage = "http://jamesrobey.com/tagmv/" #"https://github.com/foucist/tagmv/"
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ #spec.bindir = "exe"
18
+ #spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.bindir = "bin"
22
+ spec.executables = spec.files.grep(/^bin/) { |f| File.basename(f) }
23
+ spec.test_files = spec.files.grep(/^(test|spec|features)\//)
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.11"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+ spec.add_development_dependency "minitest", "~> 5.0"
28
+ spec.add_development_dependency "simplecov", "~> 0"
29
+ spec.add_development_dependency "pry", "~> 0"
30
+
31
+ spec.add_dependency "choice", "0.2.0"
32
+
33
+ end
metadata ADDED
@@ -0,0 +1,146 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tagmv
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - James Robey
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-07-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: choice
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '='
88
+ - !ruby/object:Gem::Version
89
+ version: 0.2.0
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '='
95
+ - !ruby/object:Gem::Version
96
+ version: 0.2.0
97
+ description: Moves your files into directories that represent tags, these tags are
98
+ kept organized as a hierarchy according to tag counts
99
+ email:
100
+ - james.robey+tagmv@gmail.com
101
+ executables:
102
+ - tagmv
103
+ extensions: []
104
+ extra_rdoc_files: []
105
+ files:
106
+ - ".gitignore"
107
+ - ".travis.yml"
108
+ - Gemfile
109
+ - README.md
110
+ - Rakefile
111
+ - bin/tagmv
112
+ - lib/tagmv.rb
113
+ - lib/tagmv/command_line.rb
114
+ - lib/tagmv/config.rb
115
+ - lib/tagmv/entry.rb
116
+ - lib/tagmv/filesystem.rb
117
+ - lib/tagmv/prune_path.rb
118
+ - lib/tagmv/runner.rb
119
+ - lib/tagmv/tree.rb
120
+ - lib/tagmv/version.rb
121
+ - tagmv.gemspec
122
+ homepage: http://jamesrobey.com/tagmv/
123
+ licenses:
124
+ - MIT
125
+ metadata: {}
126
+ post_install_message:
127
+ rdoc_options: []
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ requirements: []
141
+ rubyforge_project:
142
+ rubygems_version: 2.4.8
143
+ signing_key:
144
+ specification_version: 4
145
+ summary: Tag your files by moving them into a tree-like tag structure
146
+ test_files: []