feedcellar 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 99485cd81b7d2ccc7e871f93c89f54d484c1a725
4
- data.tar.gz: acf336156d13924926fe66805a457d7f6c574520
3
+ metadata.gz: e574a4dc6570abaed41db607382a859f4e99d245
4
+ data.tar.gz: 57d69eaac737b2f5369bd37cd67b8dc3e8292af2
5
5
  SHA512:
6
- metadata.gz: ce6bbda93db793f7c36e82f6461890128dbb01031a2759ca2d8491a7bcae746e71329a3b01a9eb6218b2e2dcc0508104112d8e8ea0cf0fbe3419877b844c0266
7
- data.tar.gz: 05daf037e95a72d01b876f20a8830f38d361c1cbc99bd63dc435715d84d42113473f53017964c46afb77bf8059fd79fb287fa90f1f1e6a44a1d011dcabdd492b
6
+ metadata.gz: 8a8dcd5f66b52a3036edb153abc251cef13015b77e7fd9ed3fd94b5aa6c257216d4da571bc0ba77a11e7dc3e77585b243c21ab94637dfcdab0663d90f2d2eda3
7
+ data.tar.gz: 1b9bdea33770e3959a27bedc815c4712d31d0eaefa9b3057d6d652556657bb888b9bdcf6e7c8455e7fe77f1ea0b7de2d883edc347bbd982cf8841afe18c3cd32
data/NEWS.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # NEWS
2
2
 
3
+ ## 0.2.0: 2013-06-09
4
+
5
+ Improve something to do with output release!
6
+
7
+ ### Changes
8
+
9
+ * Improvements
10
+ * Change default format of search command to one liner
11
+ * Change registers list format to one liner
12
+ * Add export command
13
+ * Add unregister command
14
+ * Use "short_text" instead of "text"
15
+ * Support raw object for API access
16
+
17
+ * Fixes
18
+ * Convert line-feed to space in feed title
19
+ * Extract parse of URL for resource of feed
20
+ * Extract parse of RSS feed
21
+ * Fix default database directory
22
+ * Fix groonga zone
23
+ * Fix description and date for atom
24
+
3
25
  ## 0.1.3: 2013-06-06
4
26
 
5
27
  Experimental functions release!
data/README.md CHANGED
@@ -32,6 +32,10 @@ Import URL from OPML
32
32
 
33
33
  $ feedcellar import registers.xml
34
34
 
35
+ Export registerd resources to OPML to STDOUT
36
+
37
+ $ feedcellar export
38
+
35
39
  Show registers
36
40
 
37
41
  $ feedcellar list
data/TODO.md CHANGED
@@ -3,5 +3,10 @@
3
3
  ## Improvements
4
4
 
5
5
  * Manage TAG outline from OPML format.
6
+ * Support pager option
7
+
8
+ ## Fixes
9
+
10
+ * Review table column types.
6
11
 
7
12
  ## Release
data/lib/feedcellar.rb CHANGED
@@ -2,6 +2,8 @@ require "feedcellar/version"
2
2
  require "feedcellar/groonga_database"
3
3
  require "feedcellar/opml"
4
4
  require "feedcellar/command"
5
+ require "feedcellar/resource"
6
+ require "feedcellar/feed"
5
7
 
6
8
  module Feedcellar
7
9
  end
@@ -1,14 +1,16 @@
1
1
  require "thor"
2
- require "rss"
3
2
  require "feedcellar/version"
4
3
  require "feedcellar/groonga_database"
5
4
  require "feedcellar/opml"
5
+ require "feedcellar/feed"
6
+ require "feedcellar/resource"
6
7
 
7
8
  module Feedcellar
8
9
  class Command < Thor
9
10
  def initialize(*args)
10
11
  super
11
- @work_dir = File.join(File.expand_path("~"), ".feedcellar")
12
+ @base_dir = File.join(File.expand_path("~"), ".feedcellar")
13
+ @database_dir = File.join(@base_dir, "db")
12
14
  end
13
15
 
14
16
  desc "version", "Show version number."
@@ -18,134 +20,93 @@ module Feedcellar
18
20
 
19
21
  desc "register URL", "Register a URL."
20
22
  def register(url)
21
- @database = GroongaDatabase.new
22
- @database.open(@work_dir) do |database|
23
- begin
24
- rss = RSS::Parser.parse(url)
25
- rescue RSS::InvalidRSSError
26
- rss = RSS::Parser.parse(url, false)
27
- rescue
28
- $stderr.puts "WARNNING: #{$!} (#{url})"
29
- return 1
30
- end
31
-
32
- unless rss
33
- $stderr.puts "ERROR: Invalid URL"
34
- return 1
35
- end
36
-
37
- resource = {}
38
- if rss.is_a?(RSS::Atom::Feed)
39
- resource["xmlUrl"] = url
40
- resource["title"] = rss.title.content
41
- resource["htmlUrl"] = rss.link.href
42
- resource["description"] = rss.dc_description
43
- else
44
- resource["xmlUrl"] = url
45
- resource["title"] = rss.channel.title
46
- resource["htmlUrl"] = rss.channel.link
47
- resource["description"] = rss.channel.description
48
- end
23
+ resource = Resource.parse(url)
24
+ return 1 unless resource
49
25
 
26
+ GroongaDatabase.new.open(@database_dir) do |database|
50
27
  database.register(resource["title"], resource)
51
28
  end
52
29
  end
53
30
 
31
+ desc "unregister TITLE_OR_URL", "Unregister a resource of feed."
32
+ def unregister(title_or_url)
33
+ GroongaDatabase.new.open(@database_dir) do |database|
34
+ database.unregister(title_or_url)
35
+ end
36
+ end
37
+
54
38
  desc "import FILE", "Import feed resources by OPML format."
55
39
  def import(opml_xml)
56
- @database = GroongaDatabase.new
57
- @database.open(@work_dir) do |database|
40
+ GroongaDatabase.new.open(@database_dir) do |database|
58
41
  Feedcellar::Opml.parse(opml_xml).each do |resource|
59
42
  database.register(resource["title"], resource)
60
43
  end
61
44
  end
62
45
  end
63
46
 
64
- desc "list", "Show feed url list."
47
+ desc "export", "Export feed resources by OPML format."
48
+ def export
49
+ GroongaDatabase.new.open(@database_dir) do |database|
50
+ puts Opml.build(database.resources.records)
51
+ end
52
+ end
53
+
54
+ desc "list", "Show registered resources list of title and URL."
65
55
  def list
66
- @database = GroongaDatabase.new
67
- @database.open(@work_dir) do |database|
56
+ GroongaDatabase.new.open(@database_dir) do |database|
68
57
  database.resources.each do |record|
69
- puts record.title
70
- puts " #{record.xmlUrl}"
71
- puts
58
+ puts "#{record.title} #{record.xmlUrl}"
72
59
  end
73
60
  end
74
61
  end
75
62
 
76
- desc "collect", "Collect feeds."
63
+ desc "collect", "Collect feeds from WWW."
77
64
  def collect
78
- @database = GroongaDatabase.new
79
- @database.open(@work_dir) do |database|
80
- resources = database.resources
81
-
82
- resources.each do |record|
65
+ GroongaDatabase.new.open(@database_dir) do |database|
66
+ database.resources.each do |record|
83
67
  feed_url = record["xmlUrl"]
84
68
  next unless feed_url
85
69
 
86
- begin
87
- rss = RSS::Parser.parse(feed_url)
88
- rescue RSS::InvalidRSSError
89
- begin
90
- rss = RSS::Parser.parse(feed_url, false)
91
- rescue
92
- $stderr.puts "WARNNING: #{$!} (#{feed_url})"
93
- next
94
- end
95
- rescue
96
- $stderr.puts "WARNNING: #{$!} (#{feed_url})"
97
- next
98
- end
99
- next unless rss
100
-
101
- rss.items.each do |item|
102
- if rss.is_a?(RSS::Atom::Feed)
103
- title = item.title.content
104
- link = item.link.href if item.link
105
- description = item.dc_description
106
- date = item.dc_date
107
- else
108
- title = item.title
109
- link = item.link
110
- description = item.description
111
- date = item.date
112
- end
113
-
114
- unless link
115
- $stderr.puts "WARNNING: missing link (#{title})"
116
- next
117
- end
118
-
119
- database.add(feed_url, title, link, description, date)
70
+ items = Feed.parse(feed_url)
71
+ next unless items
72
+
73
+ items.each do |item|
74
+ database.add(feed_url,
75
+ item.title,
76
+ item.link,
77
+ item.description,
78
+ item.date)
120
79
  end
121
80
  end
122
81
  end
123
82
  end
124
83
 
125
- desc "search WORD", "Search feeds."
84
+ desc "search WORD", "Search feeds from local database."
126
85
  option :desc, :type => :boolean, :aliases => "-d", :desc => "show description"
127
- option :simple, :type => :boolean, :desc => "simple format as one liner"
128
86
  option :browser, :type => :boolean, :desc => "open *ALL* links in browser"
129
- def search(word)
130
- @database = GroongaDatabase.new
131
- @database.open(@work_dir) do |database|
132
- feeds = @database.feeds
133
- resources = @database.resources
87
+ def search(word, api=false)
88
+ GroongaDatabase.new.open(@database_dir) do |database|
89
+ feeds = database.feeds
90
+ resources = database.resources
134
91
 
135
92
  records = feeds.select do |v|
136
93
  (v.title =~ word) | (v.description =~ word)
137
94
  end
138
95
 
139
- records.sort([{:key => "date", :order => "ascending"}]).each do |record|
96
+ sorted_records = records.sort([{:key => "date", :order => "ascending"}])
97
+ return sorted_records if api
98
+
99
+ sorted_records.each do |record|
140
100
  feed_resources = resources.select {|v| v.xmlUrl =~ record.resource }
141
101
  next unless feed_resources
142
- if options[:simple]
143
- # TODO This format will be to default from 0.2.0
102
+ next unless feed_resources.first # FIXME
103
+
104
+ unless options[:desc]
144
105
  date = record.date.strftime("%Y/%m/%d")
145
- title= record.title
106
+ title = record.title
146
107
  resource = feed_resources.first.title
147
108
  link = record.link
148
- puts "#{date} #{title} - #{resource}"
109
+ puts "#{date} #{title.gsub(/\n/, " ")} - #{resource}"
149
110
  else
150
111
  puts feed_resources.first.title
151
112
  puts " #{record.title}"
@@ -0,0 +1,52 @@
1
+ require "rss"
2
+
3
+ module Feedcellar
4
+ class Feed
5
+ attr_reader :title, :link, :description, :date
6
+ def initialize(title, link, description, date)
7
+ @title = title
8
+ @link = link
9
+ @description = description
10
+ @date = date
11
+ end
12
+
13
+ def self.parse(feed_url)
14
+ feeds = []
15
+
16
+ begin
17
+ rss = RSS::Parser.parse(feed_url)
18
+ rescue RSS::InvalidRSSError
19
+ begin
20
+ rss = RSS::Parser.parse(feed_url, false)
21
+ rescue
22
+ $stderr.puts "WARNNING: #{$!} (#{feed_url})"
23
+ return nil
24
+ end
25
+ rescue
26
+ $stderr.puts "WARNNING: #{$!} (#{feed_url})"
27
+ return nil
28
+ end
29
+ return nil unless rss
30
+
31
+ rss.items.each do |item|
32
+ if rss.is_a?(RSS::Atom::Feed)
33
+ title = item.title.content
34
+ link = item.link.href if item.link
35
+ description = item.summary.content if item.summary
36
+ date = item.updated.content if item.updated
37
+ else
38
+ title = item.title
39
+ link = item.link
40
+ description = item.description
41
+ date = item.date
42
+ end
43
+
44
+ next unless link
45
+
46
+ feeds << new(title, link, description, date)
47
+ end
48
+
49
+ feeds
50
+ end
51
+ end
52
+ end
@@ -39,6 +39,14 @@ module Feedcellar
39
39
  :date => date)
40
40
  end
41
41
 
42
+ def unregister(title_or_url)
43
+ feeds = Groonga["Resources"]
44
+ feeds.delete do |record|
45
+ (record.title == title_or_url) |
46
+ (record.xmlUrl == title_or_url)
47
+ end
48
+ end
49
+
42
50
  def close
43
51
  @database.close
44
52
  @database = nil
@@ -71,23 +79,23 @@ module Feedcellar
71
79
  Groonga::Schema.define do |schema|
72
80
  schema.create_table("Resources", :type => :hash) do |table|
73
81
  table.text("text")
74
- table.text("isComment")
75
- table.text("isBreakpoint")
76
- table.text("created")
77
- table.text("category")
82
+ table.short_text("isComment")
83
+ table.short_text("isBreakpoint")
84
+ table.short_text("created")
85
+ table.short_text("category")
78
86
  table.text("description")
79
- table.text("url")
80
- table.text("htmlUrl")
81
- table.text("xmlUrl")
82
- table.text("title")
83
- table.text("version")
84
- table.text("language")
87
+ table.short_text("url")
88
+ table.short_text("htmlUrl")
89
+ table.short_text("xmlUrl")
90
+ table.short_text("title")
91
+ table.short_text("version")
92
+ table.short_text("language")
85
93
  end
86
94
 
87
95
  schema.create_table("Feeds", :type => :hash) do |table|
88
- table.text("resource")
89
- table.text("title")
90
- table.text("link")
96
+ table.short_text("resource")
97
+ table.short_text("title")
98
+ table.short_text("link")
91
99
  table.text("description")
92
100
  table.time("date")
93
101
  end
@@ -31,5 +31,31 @@ module Feedcellar
31
31
  end
32
32
  outlines
33
33
  end
34
+
35
+ def self.build(items)
36
+ document = REXML::Document.new
37
+
38
+ xml_decl = REXML::XMLDecl.new
39
+ xml_decl.version = "1.0"
40
+ xml_decl.encoding = "UTF-8"
41
+ document.add(xml_decl)
42
+
43
+ root = document.add_element("opml")
44
+ root.add_attributes("version" => "1.0")
45
+
46
+ head = root.add_element("head")
47
+ title = head.add_element("title")
48
+ title.add_text("registers in feedcellar")
49
+
50
+ body = root.add_element("body")
51
+ items.each do |item|
52
+ outline = body.add_element("outline")
53
+ item.attributes.each do |key, value|
54
+ outline.add_attributes(key => value)
55
+ end
56
+ end
57
+
58
+ document.to_s
59
+ end
34
60
  end
35
61
  end
@@ -0,0 +1,36 @@
1
+ require "rss"
2
+
3
+ module Feedcellar
4
+ class Resource
5
+ def self.parse(url)
6
+ begin
7
+ rss = RSS::Parser.parse(url)
8
+ rescue RSS::InvalidRSSError
9
+ rss = RSS::Parser.parse(url, false)
10
+ rescue
11
+ $stderr.puts "WARNNING: #{$!} (#{url})"
12
+ return nil
13
+ end
14
+
15
+ unless rss
16
+ $stderr.puts "ERROR: Invalid URL"
17
+ return nil
18
+ end
19
+
20
+ resource = {}
21
+ if rss.is_a?(RSS::Atom::Feed)
22
+ resource["xmlUrl"] = url
23
+ resource["title"] = rss.title.content
24
+ resource["htmlUrl"] = rss.link.href
25
+ resource["description"] = rss.dc_description
26
+ else
27
+ resource["xmlUrl"] = url
28
+ resource["title"] = rss.channel.title
29
+ resource["htmlUrl"] = rss.channel.link
30
+ resource["description"] = rss.channel.description
31
+ end
32
+
33
+ resource
34
+ end
35
+ end
36
+ end
@@ -1,3 +1,3 @@
1
1
  module Feedcellar
2
- VERSION = "0.1.3"
2
+ VERSION = "0.2.0"
3
3
  end
data/test/test-command.rb CHANGED
@@ -9,10 +9,11 @@ class CommandTest < Test::Unit::TestCase
9
9
  @tmpdir = File.join(File.dirname(__FILE__), "tmp", "database")
10
10
  FileUtils.mkdir_p(@tmpdir)
11
11
  @command = Feedcellar::Command.new
12
- @command.instance_variable_set(:@work_dir, @tmpdir)
12
+ @command.instance_variable_set(:@database_dir, @tmpdir)
13
13
  end
14
14
 
15
15
  def test_command
16
+ # confirm version command
16
17
  s = ""
17
18
  io = StringIO.new(s)
18
19
  $stdout = io
@@ -20,6 +21,7 @@ class CommandTest < Test::Unit::TestCase
20
21
  assert_equal("#{Feedcellar::VERSION}\n", s)
21
22
  $stdout = STDOUT
22
23
 
24
+ # confirm register command if invalid URL
23
25
  s = ""
24
26
  io = StringIO.new(s)
25
27
  $stderr = io
@@ -27,12 +29,14 @@ class CommandTest < Test::Unit::TestCase
27
29
  assert_equal("ERROR: Invalid URL\n", s)
28
30
  $stderr = STDERR
29
31
 
32
+ # confirm register command
30
33
  @command.register("http://myokoym.github.io/entries.rss")
31
34
  @command.register("https://rubygems.org/gems/mister_fairy/versions.atom")
32
35
  Feedcellar::GroongaDatabase.new.open(@tmpdir) do |database|
33
36
  assert_equal(2, database.resources.size)
34
37
  end
35
38
 
39
+ # confirm import command
36
40
  file = File.join(File.dirname(__FILE__), "fixtures", "subscriptions.xml")
37
41
  @command.import(file)
38
42
  @command.collect
@@ -41,11 +45,48 @@ class CommandTest < Test::Unit::TestCase
41
45
  assert_true(database.feeds.count > 0)
42
46
  end
43
47
 
48
+ # confirm export command
49
+ s = ""
50
+ io = StringIO.new(s)
51
+ $stdout = io
52
+ @command.export
53
+ assert_equal(1, s.scan(/<opml/).size)
54
+ assert_equal(4, s.scan(/<outline/).size)
55
+ $stdout = STDOUT
56
+
57
+ # confirm search command
44
58
  s = ""
45
59
  io = StringIO.new(s)
46
60
  $stdout = io
47
61
  @command.search("ruby")
48
- assert_true(s.size > 500)
62
+ assert_true(s.size > 100)
63
+
64
+ # confirm search command in case of API
65
+ s = ""
66
+ io = StringIO.new(s)
67
+ ret = @command.search("ruby", true)
68
+ assert_equal(Groonga::Array, ret.class)
69
+ assert_equal(0, s.size)
70
+ assert_not_equal(0, ret.size)
71
+ $stdout = STDOUT
72
+
73
+ # confirm unregister command
74
+ @command.unregister("my_letter")
75
+ Feedcellar::GroongaDatabase.new.open(@tmpdir) do |database|
76
+ assert_equal(3, database.resources.size)
77
+ end
78
+ @command.unregister("https://rubygems.org/gems/mister_fairy/versions.atom")
79
+ Feedcellar::GroongaDatabase.new.open(@tmpdir) do |database|
80
+ assert_equal(2, database.resources.size)
81
+ end
82
+
83
+ # confirm search command after unregister
84
+ s = ""
85
+ io = StringIO.new(s)
86
+ ret = @command.search("ruby", true)
87
+ assert_equal(Groonga::Array, ret.class)
88
+ assert_equal(0, s.size)
89
+ assert_not_equal(0, ret.size)
49
90
  $stdout = STDOUT
50
91
  end
51
92
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: feedcellar
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masafumi Yokoyama
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-06-06 00:00:00.000000000 Z
11
+ date: 2013-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rroonga
@@ -127,8 +127,10 @@ files:
127
127
  - feedcellar.gemspec
128
128
  - lib/feedcellar.rb
129
129
  - lib/feedcellar/command.rb
130
+ - lib/feedcellar/feed.rb
130
131
  - lib/feedcellar/groonga_database.rb
131
132
  - lib/feedcellar/opml.rb
133
+ - lib/feedcellar/resource.rb
132
134
  - lib/feedcellar/version.rb
133
135
  - test/fixtures/subscriptions.xml
134
136
  - test/run-test.rb