clipcellar 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/NEWS.md ADDED
@@ -0,0 +1,5 @@
1
+ # NEWS
2
+
3
+ ## 0.0.1: 2014-07-29
4
+
5
+ Initial release!
@@ -0,0 +1,70 @@
1
+ # Clipcellar
2
+
3
+ Clipcellar is a full-text searchable data store for clipboard.
4
+
5
+ Powered by [GTK+][] (via [Ruby/GTK2][]) and [Groonga][] (via [Rroonga][]).
6
+
7
+ [GTK+]:http://www.gtk.org/
8
+ [Ruby/GTK2]:http://ruby-gnome2.sourceforge.jp/
9
+ [Groonga]:http://groonga.org/
10
+ [Rroonga]:http://ranguba.org/
11
+
12
+ ## Installation
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ gem 'clipcellar'
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install clipcellar
25
+
26
+ ## Usage
27
+
28
+ ### Show help
29
+
30
+ $ clipcellar
31
+
32
+ ### Add a text (or clipboard) to data store
33
+
34
+ $ clipcellar set [TEXT]
35
+
36
+ ### Add a text from files (or stdin)
37
+
38
+ $ clipcellar input [FILE]...
39
+
40
+ ### Show added texts in data store
41
+
42
+ $ clipcellar show [--gui]
43
+
44
+ ### Full-text search (and set a text to clipboard)
45
+
46
+ $ clipcellar search WORD... [--gui]
47
+
48
+ ### Watch clipboard (Ctrl+C to stop)
49
+
50
+ $ clipcellar watch
51
+
52
+ ### Delete data store and all added texts
53
+
54
+ $ clipcellar destroy
55
+
56
+ ## License
57
+
58
+ Copyright (c) 2014 Masafumi Yokoyama `<myokoym@gmail.com>`
59
+
60
+ LGPLv2.1 or later.
61
+
62
+ See LICENSE.txt or http://www.gnu.org/licenses/lgpl-2.1 for details.
63
+
64
+ ## Contributing
65
+
66
+ 1. Fork it
67
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
68
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
69
+ 4. Push to the branch (`git push origin my-new-feature`)
70
+ 5. Create new Pull Request
@@ -0,0 +1,25 @@
1
+ # Copyright (C) 2014 Masafumi Yokoyama <myokoym@gmail.com>
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ require "bundler/gem_tasks"
18
+
19
+ desc "Run test"
20
+ task :test do
21
+ Bundler::GemHelper.install_tasks
22
+ ruby("test/run-test.rb")
23
+ end
24
+
25
+ task :default => :test
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright (C) 2014 Masafumi Yokoyama <myokoym@gmail.com>
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+
19
+ require "clipcellar/command"
20
+
21
+ Clipcellar::Command.start
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'clipcellar/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "clipcellar"
8
+ spec.version = Clipcellar::VERSION
9
+ spec.authors = ["Masafumi Yokoyama"]
10
+ spec.email = ["myokoym@gmail.com"]
11
+ spec.summary = %q{Full-Text Searchable Data Store for Clipboard}
12
+ spec.description = %q{Clipcellar is a full-text searchable data store for clipboard by GTK+ (via Ruby/GTK2) and Groonga (via Rroonga).}
13
+ spec.homepage = "https://github.com/myokoym/clipcellar"
14
+ spec.license = "LGPLv2.1 or later"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) {|f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency("gtk2")
22
+ spec.add_runtime_dependency("rroonga")
23
+ spec.add_runtime_dependency("thor")
24
+
25
+ spec.add_development_dependency("test-unit")
26
+ spec.add_development_dependency("test-unit-notify")
27
+ spec.add_development_dependency("test-unit-rr")
28
+ spec.add_development_dependency("bundler", "~> 1.6")
29
+ spec.add_development_dependency("rake")
30
+ end
@@ -0,0 +1,23 @@
1
+ # Copyright (C) 2014 Masafumi Yokoyama <myokoym@gmail.com>
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ require "clipcellar/version"
18
+ require "clipcellar/groonga_database"
19
+ require "clipcellar/groonga_searcher"
20
+ require "clipcellar/clipboard"
21
+
22
+ module Clipcellar
23
+ end
@@ -0,0 +1,82 @@
1
+ # Copyright (C) 2014 Masafumi Yokoyama <myokoym@gmail.com>
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ begin
18
+ require "gtk2"
19
+ rescue Gtk::InitError
20
+ # a window system is unnecessary.
21
+ end
22
+
23
+ module Clipcellar
24
+ class Clipboard
25
+ class << self
26
+ def watch
27
+ current_text = get
28
+ GLib::Timeout.add(500) do
29
+ text = get
30
+ if current_text != text
31
+ yield(text)
32
+ current_text = text
33
+ end
34
+ true
35
+ end
36
+
37
+ begin
38
+ Gtk.main
39
+ rescue Interrupt => e
40
+ $stderr.puts(e.message)
41
+ end
42
+ end
43
+
44
+ def get
45
+ if /darwin/ =~ RUBY_PLATFORM
46
+ `pbpaste`
47
+ else
48
+ clipboard.wait_for_text
49
+ end
50
+ end
51
+
52
+ def set(text)
53
+ copy_to_clipboard(text)
54
+
55
+ # workaround for CLI
56
+ GLib::Timeout.add(1) do
57
+ Gtk.main_quit
58
+ end
59
+ Gtk.main
60
+ end
61
+
62
+ def copy_to_clipboard(text)
63
+ if /darwin/ =~ RUBY_PLATFORM
64
+ require "tempfile"
65
+ Tempfile.open(["clipcellar", "w"]) do |file|
66
+ text.each_line do |line|
67
+ file.puts(line)
68
+ end
69
+ file.flush
70
+ system("pbcopy < #{file.path}")
71
+ end
72
+ else
73
+ clipboard.text = text
74
+ end
75
+ end
76
+
77
+ def clipboard
78
+ Gtk::Clipboard.get(Gdk::Selection::CLIPBOARD)
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,158 @@
1
+ # Copyright (C) 2014 Masafumi Yokoyama <myokoym@gmail.com>
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ require "thor"
18
+ require "fileutils"
19
+ require "clipcellar/version"
20
+ require "clipcellar/groonga_database"
21
+ require "clipcellar/groonga_searcher"
22
+ require "clipcellar/clipboard"
23
+ require "clipcellar/window"
24
+
25
+ module Clipcellar
26
+ class Command < Thor
27
+ map "-v" => :version
28
+ map "-a" => :set
29
+ map "-A" => :input
30
+ map "-s" => :show
31
+ map "-S" => :search
32
+ map "-W" => :watch
33
+
34
+ attr_reader :database_dir
35
+
36
+ def initialize(*args)
37
+ super
38
+ @base_dir = File.join(File.expand_path("~"), ".clipcellar")
39
+ @database_dir = File.join(@base_dir, "db")
40
+ end
41
+
42
+ desc "version", "Show version number."
43
+ def version
44
+ puts Clipcellar::VERSION
45
+ end
46
+
47
+ desc "set [TEXT]", "Add a text (or clipboard) to data store"
48
+ def set(text=nil)
49
+ text = Clipboard.get unless text
50
+ return unless text
51
+ Clipboard.set(text)
52
+ add(text)
53
+ end
54
+
55
+ desc "input [FILE]...", "Add a text from files (or stdin)"
56
+ def input(*files)
57
+ ARGV.shift
58
+ text = ""
59
+ while line = ARGF.gets
60
+ text << line
61
+ end
62
+ Clipboard.set(text)
63
+ add(text)
64
+ end
65
+
66
+ desc "watch", "Watch clipboard to add clipboard to data store"
67
+ def watch
68
+ $stderr.puts("Watching... (Ctrl+C to Stop)")
69
+ Clipboard.watch do |text|
70
+ add(text)
71
+ end
72
+ end
73
+
74
+ desc "show [--gui]", "Show added texts in data store"
75
+ option :gui, :type => :boolean, :desc => "GUI mode"
76
+ def show
77
+ records = []
78
+ GroongaDatabase.new.open(@database_dir) do |database|
79
+ database.clipboards.each do |clipboard|
80
+ record = {}
81
+ record[:key] = clipboard._key
82
+ record[:text] = clipboard.text
83
+ record[:time] = clipboard.created_at
84
+ records << record
85
+ end
86
+ end
87
+
88
+ records.sort_by! do |record|
89
+ record[:time]
90
+ end
91
+
92
+ if options[:gui]
93
+ records.reverse!
94
+ window = Window.new(records)
95
+ window.run
96
+ else
97
+ records.each do |record|
98
+ text = record[:text]
99
+ time = record[:time].strftime("%Y-%m-%d %H:%M:%S")
100
+ formatted_text = text.gsub(/\n/, " ") if text
101
+ puts "#{time} #{formatted_text}"
102
+ end
103
+ end
104
+ end
105
+
106
+ desc "search WORD... [--gui]", "Search texts from data store"
107
+ option :gui, :type => :boolean, :desc => "GUI mode"
108
+ def search(required_word, *optional_words)
109
+ words = [required_word]
110
+ words += optional_words
111
+
112
+ records = []
113
+ GroongaDatabase.new.open(@database_dir) do |database|
114
+ reverse = options[:gui] ? true : false
115
+ sorted_clipboards = GroongaSearcher.search(database,
116
+ words,
117
+ :reverse => reverse)
118
+
119
+ sorted_clipboards.each do |clipboard|
120
+ record = {}
121
+ record[:key] = clipboard._key
122
+ record[:text] = clipboard.text
123
+ record[:time] = clipboard.created_at
124
+ records << record
125
+ end
126
+ end
127
+
128
+ if options[:gui]
129
+ window = Window.new(records)
130
+ window.run
131
+ else
132
+ text = nil
133
+ records.each do |record|
134
+ text = record[:text]
135
+ time = record[:time].strftime("%Y-%m-%d %H:%M:%S")
136
+ formatted_text = text.gsub(/\n/, " ") if text
137
+ puts "#{time} #{formatted_text}"
138
+ end
139
+ Clipboard.set(text) if text
140
+ end
141
+ end
142
+
143
+ desc "destroy", "Delete data store and all added texts"
144
+ def destroy
145
+ FileUtils.rm(Dir.glob(File.join(@database_dir, "clipcellar.db*")))
146
+ FileUtils.rmdir(@database_dir)
147
+ end
148
+
149
+ private
150
+ def add(text)
151
+ time = Time.now
152
+ id = time.strftime("%Y%m%d%H%M%S%L")
153
+ GroongaDatabase.new.open(@database_dir) do |database|
154
+ database.add(id, text, time)
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,100 @@
1
+ # Copyright (C) 2014 Masafumi Yokoyama <myokoym@gmail.com>
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ require "groonga"
18
+
19
+ module Clipcellar
20
+ class GroongaDatabase
21
+ def initialize
22
+ @database = nil
23
+ end
24
+
25
+ def open(base_path, encoding=:utf8)
26
+ reset_context(encoding)
27
+ path = File.join(base_path, "clipcellar.db")
28
+ if File.exist?(path)
29
+ @database = Groonga::Database.open(path)
30
+ populate_schema
31
+ else
32
+ FileUtils.mkdir_p(base_path)
33
+ populate(path)
34
+ end
35
+ if block_given?
36
+ begin
37
+ yield(self)
38
+ ensure
39
+ close unless closed?
40
+ end
41
+ end
42
+ end
43
+
44
+ def add(id, text, time)
45
+ clipboards.add(id,
46
+ {
47
+ :text => text,
48
+ :created_at => time,
49
+ })
50
+ end
51
+
52
+ def delete(id)
53
+ clipboards.delete(id)
54
+ end
55
+
56
+ def close
57
+ @database.close
58
+ @database = nil
59
+ end
60
+
61
+ def closed?
62
+ @database.nil? or @database.closed?
63
+ end
64
+
65
+ def clipboards
66
+ @clipboards ||= Groonga["Clipboards"]
67
+ end
68
+
69
+ def dump
70
+ Groonga::DatabaseDumper.dump
71
+ end
72
+
73
+ private
74
+ def reset_context(encoding)
75
+ Groonga::Context.default_options = {:encoding => encoding}
76
+ Groonga::Context.default = nil
77
+ end
78
+
79
+ def populate(path)
80
+ @database = Groonga::Database.create(:path => path)
81
+ populate_schema
82
+ end
83
+
84
+ def populate_schema
85
+ Groonga::Schema.define do |schema|
86
+ schema.create_table("Clipboards", :type => :hash) do |table|
87
+ table.text("text")
88
+ table.time("created_at")
89
+ end
90
+
91
+ schema.create_table("Terms",
92
+ :type => :patricia_trie,
93
+ :key_normalize => true,
94
+ :default_tokenizer => "TokenBigram") do |table|
95
+ table.index("Clipboards.text")
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end