feedcellar 0.4.1 → 0.5.0
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 +4 -4
- data/.travis.yml +0 -1
- data/NEWS.md +14 -3
- data/README.md +5 -21
- data/feedcellar.gemspec +1 -8
- data/lib/feedcellar/command.rb +2 -31
- data/lib/feedcellar/version.rb +2 -2
- metadata +1 -94
- data/config.ru +0 -34
- data/lib/feedcellar/curses_view.rb +0 -87
- data/lib/feedcellar/tree_view.rb +0 -133
- data/lib/feedcellar/views/index.haml +0 -16
- data/lib/feedcellar/views/layout.haml +0 -6
- data/lib/feedcellar/web.rb +0 -92
- data/lib/feedcellar/window.rb +0 -168
- data/test/test-curses_view.rb +0 -101
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b0b56bc49519216392bb6b0554492c44760f5c0
|
4
|
+
data.tar.gz: 3712ec8b64294e089f4cf1be5f5437f3344ea0b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73a494cdbe21660f88e8c3b85b88b5a1950d6ae36267d7d7e5d7c5d42576bdebfb518bbae7d1701a4ec02cf7bf2c640568b507a2bc52e910ad8ac5adf9127d2d
|
7
|
+
data.tar.gz: 2679352036daeeafb087b32b4a8b22b1ded9f1cd37698448b21f9812984fe081eb4c826504c6e8ac00a4858ebee1d7b3c48e28bcdea8980433eac1657a304e33
|
data/NEWS.md
CHANGED
@@ -1,16 +1,27 @@
|
|
1
1
|
# NEWS
|
2
2
|
|
3
|
+
## 0.5.0: 2015-04-05
|
4
|
+
|
5
|
+
Extract interfaces to the other projects.
|
6
|
+
|
7
|
+
### Changes
|
8
|
+
|
9
|
+
* Improvements
|
10
|
+
* Extracted Web interface to feedcellar-web gem.
|
11
|
+
* Extracted GTK+ interface to feedcellar-gtk gem.
|
12
|
+
* Extracted Curses interface to feedcellar-curses gem.
|
13
|
+
|
3
14
|
## 0.4.1: 2015-04-04
|
4
15
|
|
5
|
-
Support to paginate!
|
16
|
+
Support to paginate for Web interface!
|
6
17
|
|
7
18
|
### Changes
|
8
19
|
|
9
20
|
* Improvements
|
10
21
|
* web: Added /register.opml root.
|
11
22
|
* web: Added %p to the feed list.
|
12
|
-
* Use Padrino::Helpers.
|
13
|
-
* Introduced to paginate.
|
23
|
+
* web: Use Padrino::Helpers.
|
24
|
+
* web: Introduced to paginate.
|
14
25
|
|
15
26
|
## 0.4.0: 2014-08-29
|
16
27
|
|
data/README.md
CHANGED
@@ -45,33 +45,17 @@ Powered by [Groonga][] (via [Rroonga][]) with [Ruby][].
|
|
45
45
|
|
46
46
|
$ feedcellar search WORD1 [WORD2...]
|
47
47
|
|
48
|
-
###
|
48
|
+
### Start web server and show feeds in a web browser
|
49
49
|
|
50
|
-
|
51
|
-
|
52
|
-
Or
|
53
|
-
|
54
|
-
$ rackup
|
55
|
-
|
56
|
-
#### Enable cache (using Racknga)
|
57
|
-
|
58
|
-
$ FEEDCELLAR_ENABLE_CACHE=true rackup
|
50
|
+
[Feedcellar::Web](https://github.com/feedcellar/feedcellar-web)
|
59
51
|
|
60
52
|
### Show feeds on GUI window (experimental)
|
61
53
|
|
62
|
-
|
63
|
-
$ feedcellar show [--lines=N]
|
54
|
+
[Feedcellar::Gtk](https://github.com/feedcellar/feedcellar-gtk)
|
64
55
|
|
65
56
|
### Rich view by curses (experimental)
|
66
57
|
|
67
|
-
|
68
|
-
$ feedcellar search ruby --curses
|
69
|
-
|
70
|
-
Keybind:
|
71
|
-
j: down
|
72
|
-
k: up
|
73
|
-
f, ENTER: open the link on Firefox
|
74
|
-
q: quit
|
58
|
+
[Feedcellar::Curses](https://github.com/feedcellar/feedcellar-curses)
|
75
59
|
|
76
60
|
### Delete database
|
77
61
|
|
@@ -79,7 +63,7 @@ Or
|
|
79
63
|
|
80
64
|
## License
|
81
65
|
|
82
|
-
Copyright (c) 2013-
|
66
|
+
Copyright (c) 2013-2015 Masafumi Yokoyama `<myokoym@gmail.com>`
|
83
67
|
|
84
68
|
LGPLv2.1 or later.
|
85
69
|
|
data/feedcellar.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# feedcellar.gemspec
|
4
4
|
#
|
5
|
-
# Copyright (C) 2013-
|
5
|
+
# Copyright (C) 2013-2015 Masafumi Yokoyama <myokoym@gmail.com>
|
6
6
|
#
|
7
7
|
# This library is free software; you can redistribute it and/or
|
8
8
|
# modify it under the terms of the GNU Lesser General Public
|
@@ -39,13 +39,6 @@ Gem::Specification.new do |spec|
|
|
39
39
|
|
40
40
|
spec.add_runtime_dependency("rroonga", ">= 3.0.4")
|
41
41
|
spec.add_runtime_dependency("thor")
|
42
|
-
#spec.add_runtime_dependency("gtk2")
|
43
|
-
spec.add_runtime_dependency("sinatra")
|
44
|
-
spec.add_runtime_dependency("padrino-helpers")
|
45
|
-
spec.add_runtime_dependency("kaminari")
|
46
|
-
spec.add_runtime_dependency("haml")
|
47
|
-
spec.add_runtime_dependency("launchy")
|
48
|
-
spec.add_runtime_dependency("racknga")
|
49
42
|
|
50
43
|
spec.add_development_dependency("test-unit")
|
51
44
|
spec.add_development_dependency("test-unit-notify")
|
data/lib/feedcellar/command.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# class Feedcellar::Command
|
2
2
|
#
|
3
|
-
# Copyright (C) 2013-
|
3
|
+
# Copyright (C) 2013-2015 Masafumi Yokoyama <myokoym@gmail.com>
|
4
4
|
#
|
5
5
|
# This library is free software; you can redistribute it and/or
|
6
6
|
# modify it under the terms of the GNU Lesser General Public
|
@@ -78,21 +78,6 @@ module Feedcellar
|
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
|
-
desc "show", "Show feeds on GUI."
|
82
|
-
option :lines, :type => :numeric, :aliases => "-n", :desc => "Number of lines"
|
83
|
-
def show
|
84
|
-
# TODO: Can we always require gtk2 gem?
|
85
|
-
begin
|
86
|
-
require "feedcellar/window"
|
87
|
-
rescue LoadError => e
|
88
|
-
$stderr.puts("#{e.class}: #{e.message}")
|
89
|
-
return false
|
90
|
-
end
|
91
|
-
|
92
|
-
window = Window.new(@database_dir, options)
|
93
|
-
window.run
|
94
|
-
end
|
95
|
-
|
96
81
|
desc "list", "Show registered resources list of title and URL."
|
97
82
|
def list
|
98
83
|
GroongaDatabase.new.open(@database_dir) do |database|
|
@@ -139,7 +124,6 @@ module Feedcellar
|
|
139
124
|
option :reverse, :type => :boolean, :aliases => "-r", :desc => "reverse order while sorting"
|
140
125
|
option :mtime, :type => :numeric, :desc => "feed's data was last modified n*24 hours ago."
|
141
126
|
option :resource, :type => :string, :desc => "search of partial match by feed's resource url"
|
142
|
-
option :curses, :type => :boolean, :desc => "rich view for easy web browse"
|
143
127
|
option :grouping, :type => :boolean, :desc => "group by resource"
|
144
128
|
def search(*words)
|
145
129
|
if words.empty? &&
|
@@ -151,10 +135,7 @@ module Feedcellar
|
|
151
135
|
GroongaDatabase.new.open(@database_dir) do |database|
|
152
136
|
sorted_feeds = GroongaSearcher.search(database, words, options)
|
153
137
|
|
154
|
-
if options[:
|
155
|
-
require "feedcellar/curses_view"
|
156
|
-
CursesView.run(sorted_feeds)
|
157
|
-
elsif options[:grouping]
|
138
|
+
if options[:grouping]
|
158
139
|
sorted_feeds.group("resource").each do |group|
|
159
140
|
puts "#{group.key.title} (#{group.n_sub_records})"
|
160
141
|
end
|
@@ -173,15 +154,5 @@ module Feedcellar
|
|
173
154
|
end
|
174
155
|
end
|
175
156
|
end
|
176
|
-
|
177
|
-
desc "web", "Show feeds in a web browser"
|
178
|
-
option :silent, :type => :boolean, :desc => "Don't open in browser"
|
179
|
-
def web
|
180
|
-
require "feedcellar/web"
|
181
|
-
require "launchy"
|
182
|
-
web_server_thread = Thread.new { Feedcellar::Web.run! }
|
183
|
-
Launchy.open("http://localhost:4567") unless options[:silent]
|
184
|
-
web_server_thread.join
|
185
|
-
end
|
186
157
|
end
|
187
158
|
end
|
data/lib/feedcellar/version.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# constant Feedcellar::VERSION
|
2
2
|
#
|
3
|
-
# Copyright (C) 2013-
|
3
|
+
# Copyright (C) 2013-2015 Masafumi Yokoyama <myokoym@gmail.com>
|
4
4
|
#
|
5
5
|
# This library is free software; you can redistribute it and/or
|
6
6
|
# modify it under the terms of the GNU Lesser General Public
|
@@ -17,5 +17,5 @@
|
|
17
17
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
18
|
|
19
19
|
module Feedcellar
|
20
|
-
VERSION = "0.
|
20
|
+
VERSION = "0.5.0"
|
21
21
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: feedcellar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Masafumi Yokoyama
|
@@ -38,90 +38,6 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: sinatra
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :runtime
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: padrino-helpers
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :runtime
|
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: kaminari
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :runtime
|
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: haml
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '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'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: launchy
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
104
|
-
type: :runtime
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: racknga
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - ">="
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '0'
|
118
|
-
type: :runtime
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - ">="
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '0'
|
125
41
|
- !ruby/object:Gem::Dependency
|
126
42
|
name: test-unit
|
127
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -211,26 +127,18 @@ files:
|
|
211
127
|
- Rakefile
|
212
128
|
- bin/feedcellar
|
213
129
|
- bin/feedcellar-clear-cache
|
214
|
-
- config.ru
|
215
130
|
- feedcellar.gemspec
|
216
131
|
- lib/feedcellar.rb
|
217
132
|
- lib/feedcellar/command.rb
|
218
|
-
- lib/feedcellar/curses_view.rb
|
219
133
|
- lib/feedcellar/feed.rb
|
220
134
|
- lib/feedcellar/groonga_database.rb
|
221
135
|
- lib/feedcellar/groonga_searcher.rb
|
222
136
|
- lib/feedcellar/opml.rb
|
223
137
|
- lib/feedcellar/resource.rb
|
224
|
-
- lib/feedcellar/tree_view.rb
|
225
138
|
- lib/feedcellar/version.rb
|
226
|
-
- lib/feedcellar/views/index.haml
|
227
|
-
- lib/feedcellar/views/layout.haml
|
228
|
-
- lib/feedcellar/web.rb
|
229
|
-
- lib/feedcellar/window.rb
|
230
139
|
- test/fixtures/subscriptions.xml
|
231
140
|
- test/run-test.rb
|
232
141
|
- test/test-command.rb
|
233
|
-
- test/test-curses_view.rb
|
234
142
|
- test/test-opml.rb
|
235
143
|
homepage: http://myokoym.net/feedcellar/
|
236
144
|
licenses:
|
@@ -260,6 +168,5 @@ test_files:
|
|
260
168
|
- test/fixtures/subscriptions.xml
|
261
169
|
- test/run-test.rb
|
262
170
|
- test/test-command.rb
|
263
|
-
- test/test-curses_view.rb
|
264
171
|
- test/test-opml.rb
|
265
172
|
has_rdoc:
|
data/config.ru
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
# config.ru
|
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
|
-
base_dir = File.expand_path(File.dirname(__FILE__))
|
20
|
-
lib_dir = File.join(base_dir, "lib")
|
21
|
-
$LOAD_PATH.unshift(lib_dir)
|
22
|
-
require "feedcellar/web"
|
23
|
-
|
24
|
-
ENV["FEEDCELLAR_HOME"] ||= File.join(base_dir, ".feedcellar")
|
25
|
-
|
26
|
-
if ENV["FEEDCELLAR_ENABLE_CACHE"]
|
27
|
-
require "racknga"
|
28
|
-
require "racknga/middleware/cache"
|
29
|
-
|
30
|
-
cache_database_path = File.join(base_dir, "var", "cache", "db")
|
31
|
-
use Racknga::Middleware::Cache, :database_path => cache_database_path
|
32
|
-
end
|
33
|
-
|
34
|
-
run Feedcellar::Web
|
@@ -1,87 +0,0 @@
|
|
1
|
-
# module Feedcellar::CursesView
|
2
|
-
#
|
3
|
-
# Copyright (C) 2013-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 "curses"
|
20
|
-
|
21
|
-
module Feedcellar
|
22
|
-
module CursesView
|
23
|
-
module_function
|
24
|
-
def run(feeds)
|
25
|
-
Curses.init_screen
|
26
|
-
Curses.noecho
|
27
|
-
Curses.nonl
|
28
|
-
|
29
|
-
# TODO
|
30
|
-
feeds = feeds.to_a
|
31
|
-
feeds.reject! {|feed| feed.title.nil? }
|
32
|
-
|
33
|
-
render_feeds(feeds)
|
34
|
-
Curses.setpos(0, 0)
|
35
|
-
|
36
|
-
pos = 0
|
37
|
-
begin
|
38
|
-
loop do
|
39
|
-
case Curses.getch
|
40
|
-
when "j"
|
41
|
-
pos += 1 if pos < Curses.lines - 1
|
42
|
-
Curses.setpos(pos, 0)
|
43
|
-
when "k"
|
44
|
-
pos -= 1 if pos > 0
|
45
|
-
Curses.setpos(pos, 0)
|
46
|
-
when "f", 13
|
47
|
-
spawn("firefox",
|
48
|
-
feeds[pos].link,
|
49
|
-
[:out, :err] => "/dev/null")
|
50
|
-
when "d"
|
51
|
-
mainwin = Curses.stdscr
|
52
|
-
mainwin.clear
|
53
|
-
subwin = mainwin.subwin(mainwin.maxy, mainwin.maxx, 0, 0)
|
54
|
-
subwin.setpos(0, 0)
|
55
|
-
subwin.addstr(feeds[pos].title)
|
56
|
-
subwin.setpos(3, 0)
|
57
|
-
subwin.addstr(feeds[pos].resource.title)
|
58
|
-
subwin.setpos(6, 0)
|
59
|
-
subwin.addstr(feeds[pos].description)
|
60
|
-
subwin.refresh
|
61
|
-
Curses.getch
|
62
|
-
subwin.clear
|
63
|
-
subwin.close
|
64
|
-
render_feeds(feeds)
|
65
|
-
Curses.setpos(pos, 0)
|
66
|
-
when "q"
|
67
|
-
break
|
68
|
-
end
|
69
|
-
end
|
70
|
-
ensure
|
71
|
-
Curses.close_screen
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
module_function
|
76
|
-
def render_feeds(feeds)
|
77
|
-
feeds.each_with_index do |feed, i|
|
78
|
-
Curses.setpos(i, 0)
|
79
|
-
title = feed.title.gsub(/\n/, " ")
|
80
|
-
date = feed.date.strftime("%Y/%m/%d")
|
81
|
-
Curses.addstr("#{date} #{title}")
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
private_class_method :render_feeds
|
86
|
-
end
|
87
|
-
end
|
data/lib/feedcellar/tree_view.rb
DELETED
@@ -1,133 +0,0 @@
|
|
1
|
-
# class Feedcellar::TreeView
|
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 "gtk2"
|
20
|
-
require "erb"
|
21
|
-
|
22
|
-
module Feedcellar
|
23
|
-
class TreeView < Gtk::TreeView
|
24
|
-
KEY_COLUMN, TITLE_COLUMN, LINK_COLUMN, DESCRIPTION_COLUMN, DATE_COLUMN, STRFTIME_COLUMN, RESOURCE_AND_TITLE_COLUMN = *0..6
|
25
|
-
|
26
|
-
def initialize(records)
|
27
|
-
super()
|
28
|
-
@model = Gtk::ListStore.new(String, String, String, String, Time, String, String)
|
29
|
-
create_tree(@model, records)
|
30
|
-
end
|
31
|
-
|
32
|
-
def next
|
33
|
-
move_cursor(Gtk::MovementStep::DISPLAY_LINES, 1)
|
34
|
-
end
|
35
|
-
|
36
|
-
def prev
|
37
|
-
move_cursor(Gtk::MovementStep::DISPLAY_LINES, -1)
|
38
|
-
end
|
39
|
-
|
40
|
-
def remove_selected_record
|
41
|
-
return nil unless selected_iter
|
42
|
-
@model.remove(selected_iter)
|
43
|
-
end
|
44
|
-
|
45
|
-
def get_link(path)
|
46
|
-
@model.get_iter(path).get_value(LINK_COLUMN)
|
47
|
-
end
|
48
|
-
|
49
|
-
def selected_key
|
50
|
-
return nil unless selected_iter
|
51
|
-
selected_iter.get_value(KEY_COLUMN)
|
52
|
-
end
|
53
|
-
|
54
|
-
def selected_title
|
55
|
-
return nil unless selected_iter
|
56
|
-
selected_iter.get_value(TITLE_COLUMN)
|
57
|
-
end
|
58
|
-
|
59
|
-
def selected_link
|
60
|
-
return nil unless selected_iter
|
61
|
-
selected_iter.get_value(LINK_COLUMN)
|
62
|
-
end
|
63
|
-
|
64
|
-
def selected_description
|
65
|
-
return nil unless selected_iter
|
66
|
-
selected_iter.get_value(DESCRIPTION_COLUMN)
|
67
|
-
end
|
68
|
-
|
69
|
-
def selected_date
|
70
|
-
return nil unless selected_iter
|
71
|
-
selected_iter.get_value(DATE_COLUMN)
|
72
|
-
end
|
73
|
-
|
74
|
-
def selected_iter
|
75
|
-
selection.selected
|
76
|
-
end
|
77
|
-
|
78
|
-
def update_model(records)
|
79
|
-
model = Gtk::ListStore.new(String, String, String, String, Time, String, String)
|
80
|
-
records.each do |record|
|
81
|
-
load_record(model, record)
|
82
|
-
end
|
83
|
-
set_model(model)
|
84
|
-
@model = model
|
85
|
-
end
|
86
|
-
|
87
|
-
private
|
88
|
-
def create_tree(model, records)
|
89
|
-
set_model(model)
|
90
|
-
self.search_column = TITLE_COLUMN
|
91
|
-
self.enable_search = false
|
92
|
-
self.rules_hint = true
|
93
|
-
self.tooltip_column = DESCRIPTION_COLUMN
|
94
|
-
|
95
|
-
selection.set_mode(:browse)
|
96
|
-
|
97
|
-
records.each do |record|
|
98
|
-
load_record(model, record)
|
99
|
-
end
|
100
|
-
|
101
|
-
column = create_column("Date", STRFTIME_COLUMN)
|
102
|
-
append_column(column)
|
103
|
-
|
104
|
-
column = create_column("Title", RESOURCE_AND_TITLE_COLUMN)
|
105
|
-
append_column(column)
|
106
|
-
|
107
|
-
expand_all
|
108
|
-
end
|
109
|
-
|
110
|
-
def create_column(title, index)
|
111
|
-
column = Gtk::TreeViewColumn.new
|
112
|
-
column.title = title
|
113
|
-
renderer = Gtk::CellRendererText.new
|
114
|
-
column.pack_start(renderer, :expand => false)
|
115
|
-
column.add_attribute(renderer, :text, index)
|
116
|
-
column.set_sort_column_id(index)
|
117
|
-
column
|
118
|
-
end
|
119
|
-
|
120
|
-
def load_record(model, record)
|
121
|
-
iter = model.append
|
122
|
-
iter.set_value(KEY_COLUMN, record._key)
|
123
|
-
iter.set_value(TITLE_COLUMN, record.title)
|
124
|
-
iter.set_value(LINK_COLUMN, record.link)
|
125
|
-
escaped_description = ERB::Util.html_escape(record.description)
|
126
|
-
iter.set_value(DESCRIPTION_COLUMN, escaped_description)
|
127
|
-
iter.set_value(DATE_COLUMN, record.date)
|
128
|
-
iter.set_value(STRFTIME_COLUMN, record.date.strftime("%Y-%m-%d\n%H:%M:%S"))
|
129
|
-
text = [record.resource.title, record.title].join("\n")
|
130
|
-
iter.set_value(RESOURCE_AND_TITLE_COLUMN, text)
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
%h1 feedcellar
|
2
|
-
%p= "Powered by Groonga #{groonga_version} and Rroonga #{rroonga_version}."
|
3
|
-
%form{:action => url("/search", false, true), :method => :get}
|
4
|
-
%input{:type => "textarea", :name => "word", :size => 20, :value => params[:word]}
|
5
|
-
%input{:type => "submit", :value => "Search"}
|
6
|
-
- if @feeds
|
7
|
-
%p
|
8
|
-
- grouping(@feeds).each do |resource|
|
9
|
-
= link_to(drilled_label(resource), drilled_url(resource))
|
10
|
-
= paginate(@paginated_feeds)
|
11
|
-
%ul
|
12
|
-
- @paginated_feeds.each do |feed|
|
13
|
-
%li
|
14
|
-
%p
|
15
|
-
= link_to("#{feed.title} - #{feed.resource.title}", feed.link)
|
16
|
-
= paginate(@paginated_feeds)
|
data/lib/feedcellar/web.rb
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
# class Feedcellar::Web
|
2
|
-
#
|
3
|
-
# Copyright (C) 2014-2015 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 "sinatra/base"
|
20
|
-
require "haml"
|
21
|
-
require "padrino-helpers"
|
22
|
-
require "kaminari/sinatra"
|
23
|
-
require "feedcellar/command"
|
24
|
-
|
25
|
-
module Feedcellar
|
26
|
-
class Web < Sinatra::Base
|
27
|
-
helpers Kaminari::Helpers::SinatraHelpers
|
28
|
-
|
29
|
-
get "/" do
|
30
|
-
haml :index
|
31
|
-
end
|
32
|
-
|
33
|
-
get "/search" do
|
34
|
-
if params[:word]
|
35
|
-
words = params[:word].split(" ")
|
36
|
-
else
|
37
|
-
words = []
|
38
|
-
end
|
39
|
-
options ||= {}
|
40
|
-
options[:resource_id] = params[:resource_id] if params[:resource_id]
|
41
|
-
@feeds = search(words, options)
|
42
|
-
if @feeds
|
43
|
-
page = params[:page]
|
44
|
-
n_per_page = options[:n_per_page] || 50
|
45
|
-
@paginated_feeds = pagenate_feeds(@feeds, page, n_per_page)
|
46
|
-
end
|
47
|
-
haml :index
|
48
|
-
end
|
49
|
-
|
50
|
-
get "/registers.opml" do
|
51
|
-
content_type :xml
|
52
|
-
opml = nil
|
53
|
-
GroongaDatabase.new.open(Command.new.database_dir) do |database|
|
54
|
-
opml = Opml.build(database.resources.records)
|
55
|
-
end
|
56
|
-
opml
|
57
|
-
end
|
58
|
-
|
59
|
-
helpers do
|
60
|
-
def search(words, options={})
|
61
|
-
database = GroongaDatabase.new
|
62
|
-
database.open(Command.new.database_dir)
|
63
|
-
GroongaSearcher.search(database, words, options)
|
64
|
-
end
|
65
|
-
|
66
|
-
def pagenate_feeds(feeds, page, n_per_page)
|
67
|
-
Kaminari.paginate_array(feeds.to_a).page(page).per(n_per_page)
|
68
|
-
end
|
69
|
-
|
70
|
-
def grouping(table)
|
71
|
-
key = "resource"
|
72
|
-
table.group(key).sort_by {|item| item.n_sub_records }.reverse
|
73
|
-
end
|
74
|
-
|
75
|
-
def drilled_url(resource)
|
76
|
-
url("/search?resource_id=#{resource._id}&word=#{params[:word]}")
|
77
|
-
end
|
78
|
-
|
79
|
-
def drilled_label(resource)
|
80
|
-
"#{resource.title} (#{resource.n_sub_records})"
|
81
|
-
end
|
82
|
-
|
83
|
-
def groonga_version
|
84
|
-
Groonga::VERSION[0..2].join(".")
|
85
|
-
end
|
86
|
-
|
87
|
-
def rroonga_version
|
88
|
-
Groonga::BINDINGS_VERSION.join(".")
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
data/lib/feedcellar/window.rb
DELETED
@@ -1,168 +0,0 @@
|
|
1
|
-
# class Feedcellar::Window
|
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 "gtk2"
|
20
|
-
require "feedcellar/tree_view"
|
21
|
-
require "feedcellar/command"
|
22
|
-
require "feedcellar/groonga_database"
|
23
|
-
require "feedcellar/groonga_searcher"
|
24
|
-
|
25
|
-
module Feedcellar
|
26
|
-
class Window < Gtk::Window
|
27
|
-
def initialize(database_dir, options)
|
28
|
-
super()
|
29
|
-
@database = GroongaDatabase.new
|
30
|
-
@database.open(database_dir)
|
31
|
-
@options = options
|
32
|
-
self.title = "Feedcellar"
|
33
|
-
set_default_size(640, 480)
|
34
|
-
signal_connect("destroy") do
|
35
|
-
@database.close unless @database.closed?
|
36
|
-
Gtk.main_quit
|
37
|
-
end
|
38
|
-
|
39
|
-
@vbox = Gtk::VBox.new
|
40
|
-
add(@vbox)
|
41
|
-
|
42
|
-
@entry_hbox = Gtk::HBox.new
|
43
|
-
@vbox.pack_start(@entry_hbox, false, false, 0)
|
44
|
-
|
45
|
-
@entry = Gtk::Entry.new
|
46
|
-
@entry_hbox.add(@entry)
|
47
|
-
@search_button = Gtk::Button.new("Search")
|
48
|
-
@search_button.signal_connect("clicked") do
|
49
|
-
words = @entry.text.split(" ")
|
50
|
-
records = search(words, @options)
|
51
|
-
@tree_view.update_model(records)
|
52
|
-
end
|
53
|
-
@entry_hbox.add(@search_button)
|
54
|
-
|
55
|
-
@scrolled_window = Gtk::ScrolledWindow.new
|
56
|
-
@scrolled_window.set_policy(:automatic, :automatic)
|
57
|
-
@vbox.pack_start(@scrolled_window, true, true, 0)
|
58
|
-
|
59
|
-
records = all_records(options)
|
60
|
-
|
61
|
-
@tree_view = TreeView.new(records)
|
62
|
-
@scrolled_window.add(@tree_view)
|
63
|
-
|
64
|
-
@label = Gtk::Label.new
|
65
|
-
@label.text = "Double Click or Press Return: Open a Link into Browser/ Ctrl+d: Delete from Data Store"
|
66
|
-
@vbox.pack_start(@label, false, false, 0)
|
67
|
-
|
68
|
-
@tree_view.signal_connect("row-activated") do |tree_view, path, column|
|
69
|
-
show_uri(@tree_view.selected_link)
|
70
|
-
end
|
71
|
-
|
72
|
-
define_key_bindings
|
73
|
-
end
|
74
|
-
|
75
|
-
def run
|
76
|
-
show_all
|
77
|
-
Gtk.main
|
78
|
-
end
|
79
|
-
|
80
|
-
private
|
81
|
-
def search(words, options)
|
82
|
-
records = GroongaSearcher.search(@database, words, options)
|
83
|
-
if options[:lines]
|
84
|
-
records.take(options[:lines])
|
85
|
-
else
|
86
|
-
records
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def all_records(options)
|
91
|
-
search(nil, options)
|
92
|
-
end
|
93
|
-
|
94
|
-
def define_key_bindings
|
95
|
-
signal_connect("key-press-event") do |widget, event|
|
96
|
-
handled = false
|
97
|
-
|
98
|
-
if event.state.control_mask?
|
99
|
-
handled = action_from_keyval_with_control_mask(event.keyval)
|
100
|
-
else
|
101
|
-
handled = action_from_keyval(event.keyval)
|
102
|
-
end
|
103
|
-
|
104
|
-
handled
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def action_from_keyval(keyval)
|
109
|
-
case keyval
|
110
|
-
when Gdk::Keyval::GDK_KEY_n
|
111
|
-
@tree_view.next
|
112
|
-
when Gdk::Keyval::GDK_KEY_p
|
113
|
-
@tree_view.prev
|
114
|
-
when Gdk::Keyval::GDK_KEY_Return
|
115
|
-
show_uri(@tree_view.selected_link)
|
116
|
-
when Gdk::Keyval::GDK_KEY_h
|
117
|
-
@scrolled_window.hadjustment.value -= 17
|
118
|
-
when Gdk::Keyval::GDK_KEY_j
|
119
|
-
@scrolled_window.vadjustment.value += 17
|
120
|
-
when Gdk::Keyval::GDK_KEY_k
|
121
|
-
@scrolled_window.vadjustment.value -= 17
|
122
|
-
when Gdk::Keyval::GDK_KEY_l
|
123
|
-
@scrolled_window.hadjustment.value += 17
|
124
|
-
when Gdk::Keyval::GDK_KEY_q
|
125
|
-
destroy
|
126
|
-
else
|
127
|
-
return false
|
128
|
-
end
|
129
|
-
true
|
130
|
-
end
|
131
|
-
|
132
|
-
def action_from_keyval_with_control_mask(keyval)
|
133
|
-
case keyval
|
134
|
-
when Gdk::Keyval::GDK_KEY_n
|
135
|
-
10.times { @tree_view.next }
|
136
|
-
when Gdk::Keyval::GDK_KEY_p
|
137
|
-
10.times { @tree_view.prev }
|
138
|
-
when Gdk::Keyval::GDK_KEY_d
|
139
|
-
key = @tree_view.selected_key
|
140
|
-
if key
|
141
|
-
# TODO: don't want to use Command class.
|
142
|
-
GroongaDatabase.new.open(Command.new.database_dir) do |database|
|
143
|
-
database.delete(key)
|
144
|
-
end
|
145
|
-
@tree_view.remove_selected_record
|
146
|
-
end
|
147
|
-
else
|
148
|
-
return false
|
149
|
-
end
|
150
|
-
true
|
151
|
-
end
|
152
|
-
|
153
|
-
def show_uri(uri)
|
154
|
-
case RUBY_PLATFORM
|
155
|
-
when /darwin/
|
156
|
-
system("open", uri)
|
157
|
-
when /mswin|mingw|cygwin|bccwin/
|
158
|
-
system("start", uri)
|
159
|
-
else
|
160
|
-
if Gtk.respond_to?(:show_uri)
|
161
|
-
Gtk.show_uri(uri)
|
162
|
-
else
|
163
|
-
system("firefox", uri)
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
data/test/test-curses_view.rb
DELETED
@@ -1,101 +0,0 @@
|
|
1
|
-
# class CursesViewTest
|
2
|
-
#
|
3
|
-
# Copyright (C) 2013-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 "feedcellar/curses_view"
|
20
|
-
|
21
|
-
class CursesViewTest < Test::Unit::TestCase
|
22
|
-
def setup
|
23
|
-
@feeds = [
|
24
|
-
Feed.new("title", "http://example.net/post1", "desc1"),
|
25
|
-
Feed.new("title", "http://example.net/post2", "desc2"),
|
26
|
-
]
|
27
|
-
end
|
28
|
-
|
29
|
-
def test_run_quit
|
30
|
-
mock(Curses).getch { "q" }
|
31
|
-
assert_nothing_raised do
|
32
|
-
Feedcellar::CursesView.run(@feeds)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def test_run_down
|
37
|
-
mock(Curses).getch { "j" }
|
38
|
-
mock(Curses).getch { "q" }
|
39
|
-
assert_nothing_raised do
|
40
|
-
Feedcellar::CursesView.run(@feeds)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def test_run_up
|
45
|
-
mock(Curses).getch { "k" }
|
46
|
-
mock(Curses).getch { "q" }
|
47
|
-
assert_nothing_raised do
|
48
|
-
Feedcellar::CursesView.run(@feeds)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def test_run_firefox
|
53
|
-
mock(Curses).getch { "f" }
|
54
|
-
mock(Feedcellar::CursesView).spawn("firefox",
|
55
|
-
@feeds[0].link,
|
56
|
-
[:out, :err] => "/dev/null")
|
57
|
-
mock(Curses).getch { "q" }
|
58
|
-
assert_nothing_raised do
|
59
|
-
Feedcellar::CursesView.run(@feeds)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def test_run_down_and_firefox
|
64
|
-
mock(Curses).getch { "j" }
|
65
|
-
mock(Curses).getch { "f" }
|
66
|
-
mock(Feedcellar::CursesView).spawn("firefox",
|
67
|
-
@feeds[1].link,
|
68
|
-
[:out, :err] => "/dev/null")
|
69
|
-
mock(Curses).getch { "q" }
|
70
|
-
assert_nothing_raised do
|
71
|
-
Feedcellar::CursesView.run(@feeds)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def test_run_description
|
76
|
-
mock(Curses).getch { "d" }
|
77
|
-
mock(Curses).getch { "q" }
|
78
|
-
mock(Curses).getch { "q" }
|
79
|
-
assert_nothing_raised do
|
80
|
-
Feedcellar::CursesView.run(@feeds)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
class Feed
|
85
|
-
attr_reader :title, :link, :date, :description, :resource
|
86
|
-
def initialize(title, link, description)
|
87
|
-
@title = title
|
88
|
-
@link = link
|
89
|
-
@date = Time.now
|
90
|
-
@description = description
|
91
|
-
@resource = Resource.new("Web Site's Title")
|
92
|
-
end
|
93
|
-
|
94
|
-
class Resource
|
95
|
-
attr_reader :title
|
96
|
-
def initialize(title)
|
97
|
-
@title = title
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|