fuzzy_notes 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+