fuzzy_notes 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.
data/README ADDED
@@ -0,0 +1 @@
1
+ README
data/TODO ADDED
@@ -0,0 +1,2 @@
1
+ TODO:
2
+ -Evernote support
data/bin/fnote ADDED
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'yaml'
5
+ require 'rubygems'
6
+ require 'fuzzy_notes'
7
+
8
+ CONFIG_PATH = "#{ENV['HOME']}/.fuzzy_notes"
9
+
10
+ options = {}
11
+ need_extra_args = [:print, :edit, :encrypt, :decrypt]
12
+ optparse = OptionParser.new do |opts|
13
+ opts.banner = "Usage: fnote [options] [keyword1, keyword2...]"
14
+
15
+ opts.on("-c", "--config [CONFIG]", "Specify config file") { |opt| options[:config] = opt}
16
+ opts.on("-p", "--print", "Dump matching notes to stdout") { |opt| options[:print] = true }
17
+ opts.on("-l", "--list", "List statistics for matching notes") { |opt| options[:list] = true }
18
+ opts.on("-i", "--info", "Alias for 'list'") { |opt| options[:info] = true }
19
+ opts.on("-s", "--search", "Perform a full text search when matching notes") { |opt| options[:search] = true }
20
+ opts.on("-v", "--verbose", "Enable debug output") { |opt| options[:verbose] = true }
21
+ opts.on("-e", "--encrypt", "Encrypt matching notes") { |opt| options[:encrypt] = true }
22
+ opts.on("-d", "--decrypt", "Decrypt matching notes") { |opt| options[:decrypt] = true }
23
+ opts.on("-h", "--help", "Show this message") {
24
+ puts opts
25
+ exit
26
+ }
27
+ end
28
+
29
+ begin
30
+ optparse.parse!(ARGV)
31
+ options[:edit] = true if options.values.compact.empty?
32
+ # check for extra args if necessary
33
+ if need_extra_args.any? {|opt| options[opt]} && ARGV.empty?
34
+ puts optparse
35
+ exit
36
+ end
37
+ rescue OptionParser::ParseError => e
38
+ puts optparse
39
+ end
40
+
41
+ config_path = \
42
+ options[:config] && File.exists?(options[:config]) && options[:config] ||
43
+ File.exists?(CONFIG_PATH) && CONFIG_PATH
44
+
45
+ config = config_path ? YAML::load_file(config_path) : {}
46
+ puts "Warning: config file not found, using defaults" if config.empty?
47
+
48
+ notes = FuzzyNotes::Notes.new(:log_level => (options[:verbose] || config[:verbose]) ? 0 : 1,
49
+ :note_paths => config[:note_paths],
50
+ :full_text_search => options[:search] || config[:full_text_search],
51
+ :keywords => ARGV)
52
+
53
+ if options[:list] || options[:info]
54
+ notes.info
55
+ elsif options[:print]
56
+ notes.cat
57
+ elsif options[:encrypt]
58
+ notes.encrypt
59
+ elsif options[:decrypt]
60
+ notes.decrypt
61
+ else
62
+ notes.edit
63
+ end
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+
3
+ module FuzzyNotes; end
4
+
5
+ require 'fuzzy_notes/logger'
6
+ require 'fuzzy_notes/notes'
7
+ require 'fuzzy_notes/fuzzy_finder'
@@ -0,0 +1,42 @@
1
+ require 'find'
2
+
3
+ class FuzzyNotes::FuzzyFinder
4
+ extend FuzzyNotes::Logger
5
+ private_class_method :new
6
+
7
+ def self.find(path, params = {})
8
+ keywords, extensions, search = params.values_at(:keywords, :extensions, :full_text_search)
9
+ match_proc = method(search ? :full_text_match? : :file_name_match?)
10
+ log.debug "[debug] search path: #{path}"
11
+
12
+ all_files, matching_files = [], []
13
+ Find.find(*path) do |file_path|
14
+ if extension_match?(file_path, extensions)
15
+ all_files << file_path
16
+ matching_files << file_path if match_proc.call(file_path, keywords)
17
+ end
18
+ end
19
+
20
+ [all_files.sort, matching_files.sort]
21
+ end
22
+
23
+ private
24
+
25
+ def self.extension_match?(file_path, extensions)
26
+ file_name = File.basename(file_path)
27
+ !extensions || extensions.any? {|ext| /\.#{ext}$/ === file_name }
28
+ end
29
+
30
+ def self.file_name_match?(file_path, keywords)
31
+ keywords ? keywords.any? { |name| /#{name}/ === file_path } : false
32
+ end
33
+
34
+ def self.full_text_match?(file_path, keywords)
35
+ if keywords && !keywords.empty?
36
+ file_contents = File.read(file_path)
37
+ keywords.any? { |key| /#{key}/m === file_contents }
38
+ else false
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,21 @@
1
+ require 'buffered_logger'
2
+
3
+ class FuzzyNotes::Log
4
+ LOG_LEVEL = 1
5
+
6
+ private_class_method :new
7
+
8
+ def self.init_log(log_level)
9
+ @log = BufferedLogger.new(STDOUT, log_level)
10
+ end
11
+
12
+ def self.log
13
+ @log ||= BufferedLogger.new(STDOUT, LOG_LEVEL)
14
+ end
15
+ end
16
+
17
+ module FuzzyNotes::Logger
18
+ def log
19
+ FuzzyNotes::Log.log
20
+ end
21
+ end
@@ -0,0 +1,116 @@
1
+ require 'gibberish'
2
+
3
+ class FuzzyNotes::Notes
4
+ include FuzzyNotes::Logger
5
+
6
+ INIT_PARAMS = :log_level, :editor, :note_paths, :valid_extensions, :keywords
7
+
8
+ # param defaults
9
+ #
10
+ LOG_LEVEL = 1
11
+ EDITOR='vim'
12
+ NOTE_PATHS=[ "#{ENV['HOME']}/notes" ]
13
+ VALID_EXTENSIONS=%w( txt enc )
14
+ KEYWORDS = []
15
+
16
+ attr_reader :notes, :all_notes
17
+
18
+ def initialize(params = {})
19
+ parse_init_params(params)
20
+
21
+ unless @note_paths.any? { |p| File.exists?(p) }
22
+ log.error "ERROR: no valid note paths found"
23
+ exit
24
+ end
25
+
26
+ @all_notes, @notes = \
27
+ FuzzyNotes::FuzzyFinder.find(@note_paths, { :keywords => @keywords,
28
+ :extensions => @extensions,
29
+ :full_text_search => params[:full_text_search] })
30
+ end
31
+
32
+ def parse_init_params(params)
33
+ INIT_PARAMS.each do |param|
34
+ klass = self.class
35
+ klass.send(:attr_reader, param)
36
+ const_name = param.to_s.upcase
37
+ instance_variable_set("@#{param}", params[param] ||
38
+ (klass.const_defined?(const_name) ? klass.const_get(const_name) : nil) )
39
+ end
40
+ FuzzyNotes::Log.init_log(@log_level)
41
+
42
+ ivar_values = instance_variables.inject("") { |s, ivar| s << " #{ivar} => #{eval(ivar).inspect}\n" }
43
+ log.debug "[debug] init attributes: \n#{ivar_values}"
44
+ end
45
+
46
+
47
+ # cat all matching notes to stdout
48
+ def cat
49
+ notes.each do |n|
50
+ puts "=== #{n} ===\n\n"
51
+ puts "#{File.read(n)}\n"
52
+ end
53
+ end
54
+
55
+
56
+ # edit all matching notes in EDITOR
57
+ def edit
58
+ exec("#{editor} #{bashify_paths(notes)}") if !notes.empty?
59
+ end
60
+
61
+
62
+ def encrypt
63
+ apply_cipher
64
+ end
65
+
66
+
67
+ def decrypt
68
+ apply_cipher(true)
69
+ end
70
+
71
+
72
+ # view WC info for all/matching notes
73
+ def info
74
+ paths = bashify_paths(notes.empty? ? all_notes : notes)
75
+ puts `wc $(find #{paths} -type f)`
76
+ end
77
+
78
+
79
+ private
80
+
81
+
82
+ def apply_cipher(decrypt = false)
83
+ extension, action = decrypt ? ['.txt', 'dec'] : ['.enc', 'enc']
84
+ password = get_password
85
+ cipher = Gibberish::AES.new(password)
86
+ notes.each do |note|
87
+ log.info "#{action} '#{note}'"
88
+ pathname = File.dirname(note)
89
+ filename = File.basename(note, '.*')
90
+ begin
91
+ ciphertext = cipher.send(action, File.read(note))
92
+ log.debug "[debug] writing encrypted content to: #{pathname}/#{filename}#{extension}"
93
+ File.open("#{pathname}/#{filename}#{extension}", 'w') { |f| f << ciphertext }
94
+ log.debug "[debug] deleting unencrypted file: #{note}"
95
+ File.delete(note)
96
+ rescue OpenSSL::Cipher::CipherError => e
97
+ log.error "ERROR: #{e}"
98
+ end
99
+ end
100
+ end
101
+
102
+
103
+ def get_password
104
+ printf 'Enter password (will not be shown):'
105
+ `stty -echo`; password = STDIN.gets.strip;`stty echo`; puts
106
+ log.debug "[debug] entered password: #{password.inspect}"
107
+ password
108
+ end
109
+
110
+
111
+ # lists matching note paths in bash style, space seperated fashion
112
+ def bashify_paths(paths)
113
+ paths.map {|n| "\"#{n}\""}.join(' ')
114
+ end
115
+
116
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fuzzy_notes
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Alex Skryl
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-06-24 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: gibberish
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: buffered_logger
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ description: A note manager with fuzzy search, full text search, and encryption capabilities
50
+ email: rut216@gmail.com
51
+ executables:
52
+ - fnote
53
+ extensions: []
54
+
55
+ extra_rdoc_files: []
56
+
57
+ files:
58
+ - lib/fuzzy_notes/fuzzy_finder.rb
59
+ - lib/fuzzy_notes/logger.rb
60
+ - lib/fuzzy_notes/notes.rb
61
+ - lib/fuzzy_notes.rb
62
+ - bin/fnote
63
+ - README
64
+ - TODO
65
+ has_rdoc: true
66
+ homepage: http://github.com/skryl
67
+ licenses: []
68
+
69
+ post_install_message:
70
+ rdoc_options: []
71
+
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ hash: 3
80
+ segments:
81
+ - 0
82
+ version: "0"
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ hash: 3
89
+ segments:
90
+ - 0
91
+ version: "0"
92
+ requirements: []
93
+
94
+ rubyforge_project:
95
+ rubygems_version: 1.6.2
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: A plain text note manager
99
+ test_files: []
100
+