automatic 14.12.2 → 26.08

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.
Files changed (172) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +635 -83
  3. data/VERSION +1 -1
  4. data/automatic.gemspec +109 -248
  5. data/bin/automatic +20 -139
  6. data/config/feed2console.yml +10 -4
  7. data/config/feed2markdown.yml +41 -0
  8. data/doc/AI_TUTORIAL.md +518 -0
  9. data/doc/BASIC_DESIGN.md +516 -0
  10. data/doc/COPYING.LESSER +165 -0
  11. data/doc/DEPLOYMENT.md +824 -0
  12. data/doc/LICENSE.md +14 -0
  13. data/doc/PLUGINS.md +1875 -0
  14. data/doc/PLUGIN_DEVELOPMENT.md +86 -0
  15. data/doc/POLICY.md +857 -0
  16. data/doc/QUICKSTART.md +256 -0
  17. data/doc/RELEASING.md +381 -0
  18. data/doc/REQUIREMENTS.md +526 -0
  19. data/doc/VERSIONS +208 -0
  20. data/lib/automatic/cli.rb +248 -0
  21. data/lib/automatic/environment.rb +31 -5
  22. data/lib/automatic/feed_maker.rb +10 -9
  23. data/lib/automatic/feed_parser.rb +51 -35
  24. data/lib/automatic/http.rb +107 -0
  25. data/lib/automatic/log.rb +49 -18
  26. data/lib/automatic/opml.rb +3 -1
  27. data/lib/automatic/pipeline.rb +63 -32
  28. data/lib/automatic/recipe.rb +56 -17
  29. data/lib/automatic/version.rb +14 -1
  30. data/lib/automatic.rb +78 -20
  31. data/plugins/custom_feed/svn_log.rb +73 -32
  32. data/plugins/custom_feed/web.rb +348 -0
  33. data/plugins/filter/absolute_uri.rb +43 -27
  34. data/plugins/filter/accept.rb +38 -45
  35. data/plugins/filter/claude.rb +217 -0
  36. data/plugins/filter/clear.rb +12 -8
  37. data/plugins/filter/description_link.rb +49 -51
  38. data/plugins/filter/full_feed.rb +158 -52
  39. data/plugins/filter/gemini.rb +216 -0
  40. data/plugins/filter/github_feed.rb +38 -26
  41. data/plugins/filter/ignore.rb +33 -44
  42. data/plugins/filter/image.rb +36 -25
  43. data/plugins/filter/image_source.rb +58 -52
  44. data/plugins/filter/join.rb +107 -0
  45. data/plugins/filter/one.rb +19 -26
  46. data/plugins/filter/open_ai.rb +198 -0
  47. data/plugins/filter/rand.rb +16 -17
  48. data/plugins/filter/sakura_ai.rb +205 -0
  49. data/plugins/filter/sanitize.rb +29 -34
  50. data/plugins/filter/sort.rb +20 -27
  51. data/plugins/filter/tumblr_resize.rb +31 -23
  52. data/plugins/notify/ikachan.rb +86 -48
  53. data/plugins/provide/fluentd.rb +43 -24
  54. data/plugins/publish/amazon_s3.rb +73 -40
  55. data/plugins/publish/console.rb +19 -16
  56. data/plugins/publish/console_link.rb +20 -17
  57. data/plugins/publish/eject.rb +48 -26
  58. data/plugins/publish/fluentd.rb +50 -30
  59. data/plugins/publish/hatena_bookmark.rb +88 -71
  60. data/plugins/publish/instapaper.rb +69 -59
  61. data/plugins/publish/markdown.rb +278 -0
  62. data/plugins/publish/memcached.rb +35 -29
  63. data/plugins/store/database.rb +50 -48
  64. data/plugins/store/digest.rb +212 -0
  65. data/plugins/store/file.rb +99 -68
  66. data/plugins/store/full_text.rb +32 -25
  67. data/plugins/store/permalink.rb +18 -22
  68. data/plugins/subscription/feed.rb +34 -21
  69. data/plugins/subscription/link.rb +31 -32
  70. data/plugins/subscription/text.rb +32 -46
  71. data/plugins/subscription/tumblr.rb +55 -44
  72. data/plugins/subscription/xml.rb +40 -36
  73. metadata +108 -321
  74. data/Gemfile +0 -38
  75. data/Rakefile +0 -59
  76. data/doc/ChangeLog +0 -303
  77. data/doc/PLUGINS +0 -750
  78. data/doc/PLUGINS.ja +0 -753
  79. data/doc/README +0 -511
  80. data/doc/README.ja +0 -519
  81. data/plugins/filter/google_news.rb +0 -50
  82. data/plugins/publish/google_calendar.rb +0 -84
  83. data/plugins/publish/hipchat.rb +0 -46
  84. data/plugins/publish/pocket.rb +0 -45
  85. data/plugins/publish/twitter.rb +0 -58
  86. data/plugins/subscription/chan_toru.rb +0 -57
  87. data/plugins/subscription/g_guide.rb +0 -57
  88. data/plugins/subscription/pocket.rb +0 -51
  89. data/plugins/subscription/twitter.rb +0 -69
  90. data/plugins/subscription/twitter_search.rb +0 -50
  91. data/plugins/subscription/weather.rb +0 -33
  92. data/script/build +0 -84
  93. data/spec/fixtures/sampleFeeds.tsv +0 -1
  94. data/spec/fixtures/sampleFeeds2.tsv +0 -2
  95. data/spec/fixtures/sampleRecipe.yml +0 -24
  96. data/spec/lib/automatic/log_spec.rb +0 -32
  97. data/spec/lib/automatic/pipeline_spec.rb +0 -68
  98. data/spec/lib/automatic/recipe_spec.rb +0 -40
  99. data/spec/lib/automatic_spec.rb +0 -99
  100. data/spec/plugins/custom_feed/svn_log_spec.rb +0 -31
  101. data/spec/plugins/filter/absolute_uri_spec.rb +0 -61
  102. data/spec/plugins/filter/accept_spec.rb +0 -331
  103. data/spec/plugins/filter/clear_spec.rb +0 -49
  104. data/spec/plugins/filter/description_link_spec.rb +0 -138
  105. data/spec/plugins/filter/full_feed_spec.rb +0 -129
  106. data/spec/plugins/filter/github_feed_spec.rb +0 -55
  107. data/spec/plugins/filter/google_news_spec.rb +0 -69
  108. data/spec/plugins/filter/ignore_spec.rb +0 -328
  109. data/spec/plugins/filter/image_source_spec.rb +0 -89
  110. data/spec/plugins/filter/image_spec.rb +0 -65
  111. data/spec/plugins/filter/one_spec.rb +0 -71
  112. data/spec/plugins/filter/rand_spec.rb +0 -52
  113. data/spec/plugins/filter/sanitize_spec.rb +0 -153
  114. data/spec/plugins/filter/sort_spec.rb +0 -189
  115. data/spec/plugins/filter/tumblr_resize_spec.rb +0 -109
  116. data/spec/plugins/notify/ikachan_spec.rb +0 -58
  117. data/spec/plugins/provide/fluentd_spec.rb +0 -49
  118. data/spec/plugins/publish/amazon_s3_spec.rb +0 -40
  119. data/spec/plugins/publish/console_spec.rb +0 -30
  120. data/spec/plugins/publish/eject_spec.rb +0 -40
  121. data/spec/plugins/publish/fluentd_spec.rb +0 -40
  122. data/spec/plugins/publish/google_calendar_spec.rb +0 -83
  123. data/spec/plugins/publish/hatena_bookmark_spec.rb +0 -134
  124. data/spec/plugins/publish/hipchat_spec.rb +0 -69
  125. data/spec/plugins/publish/instapaper_spec.rb +0 -82
  126. data/spec/plugins/publish/memcached_spec.rb +0 -63
  127. data/spec/plugins/publish/pocket_spec.rb +0 -51
  128. data/spec/plugins/publish/twitter_spec.rb +0 -73
  129. data/spec/plugins/store/file_spec.rb +0 -58
  130. data/spec/plugins/store/full_text_spec.rb +0 -152
  131. data/spec/plugins/store/permalink_spec.rb +0 -206
  132. data/spec/plugins/subscription/chan_toru_spec.rb +0 -56
  133. data/spec/plugins/subscription/feed_spec.rb +0 -71
  134. data/spec/plugins/subscription/g_guide_spec.rb +0 -82
  135. data/spec/plugins/subscription/link_spec.rb +0 -72
  136. data/spec/plugins/subscription/pocket_spec.rb +0 -57
  137. data/spec/plugins/subscription/text_spec.rb +0 -84
  138. data/spec/plugins/subscription/tumblr_spec.rb +0 -74
  139. data/spec/plugins/subscription/twitter_search_spec.rb +0 -57
  140. data/spec/plugins/subscription/twitter_spec.rb +0 -73
  141. data/spec/plugins/subscription/weather_spec.rb +0 -44
  142. data/spec/plugins/subscription/xml_spec.rb +0 -84
  143. data/spec/spec_helper.rb +0 -106
  144. data/spec/user_dir/plugins/store/mock.rb +0 -16
  145. data/test/fixtures/sampleOPML.xml +0 -11
  146. data/test/integration/test_absoluteurl.yml +0 -25
  147. data/test/integration/test_activerecord.yml +0 -24
  148. data/test/integration/test_add_pocket.yml +0 -26
  149. data/test/integration/test_chan_toru.yml +0 -21
  150. data/test/integration/test_descriptionlink.yml +0 -21
  151. data/test/integration/test_fluentd.yml +0 -22
  152. data/test/integration/test_fulltext.yml +0 -30
  153. data/test/integration/test_google_news.yml +0 -21
  154. data/test/integration/test_googlealert.yml +0 -21
  155. data/test/integration/test_hatenabookmark.yml +0 -30
  156. data/test/integration/test_ignore.yml +0 -25
  157. data/test/integration/test_ignore2.yml +0 -22
  158. data/test/integration/test_image2local.yml +0 -33
  159. data/test/integration/test_instapaper.yml +0 -26
  160. data/test/integration/test_link2local.yml +0 -34
  161. data/test/integration/test_one.yml +0 -23
  162. data/test/integration/test_pocket.yml +0 -22
  163. data/test/integration/test_rand.yml +0 -21
  164. data/test/integration/test_sanitize.yml +0 -23
  165. data/test/integration/test_sort.yml +0 -36
  166. data/test/integration/test_svnlog.yml +0 -15
  167. data/test/integration/test_text2feed.yml +0 -36
  168. data/test/integration/test_tumblr2local.yml +0 -43
  169. data/test/integration/test_twitter_search.yml +0 -22
  170. data/test/integration/test_weather.yml +0 -19
  171. data/test/integration/test_xml2fluentd.yml +0 -21
  172. data/vendor/.gitkeep +0 -0
@@ -1,47 +1,46 @@
1
1
  # -*- coding: utf-8 -*-
2
- # Name:: Automatic::Plugin::Subscription::Link
3
- # Author:: 774 <http://id774.net>
4
- # Created:: Sep 18, 2012
5
- # Updated:: Oct 29, 2014
6
- # Copyright:: Copyright (c) 2012-2014 Automatic Ruby Developers.
7
- # License:: Licensed under the GNU GENERAL PUBLIC LICENSE, Version 3.0.
2
+ # Name:: Automatic::Plugin::Subscription::Link
3
+ # Author: id774 (More info: http://id774.net)
4
+ # Source Code:: https://github.com/id774/automaticruby
5
+ # License:: The GPL version 3, or LGPL version 3 (Dual License).
6
+ # Contact:: idnanashi@gmail.com
7
+ # Created:: Sep 18, 2012
8
+ # Updated:: Aug 15, 2026
9
+ # Copyright:: Copyright (c) 2012-2026 Automatic Ruby Developers.
8
10
 
9
11
  module Automatic::Plugin
10
12
  class SubscriptionLink
11
- require 'open-uri'
12
- require 'rss'
13
-
14
- def initialize(config, pipeline=[])
15
- @config = config
13
+ def initialize(config, pipeline = [])
14
+ @config = config || {}
16
15
  @pipeline = pipeline
17
16
  end
18
17
 
18
+ # Returns only what it fetched, discarding any incoming pipeline.
19
19
  def run
20
- @return_feeds = []
21
- @config['urls'].each {|url|
22
- retries = 0
23
- retry_max = @config['retry'].to_i || 0
24
- begin
25
- create_rss(URI::Parser.new.escape(url))
26
- rescue
27
- retries += 1
28
- Automatic::Log.puts("error", "ErrorCount: #{retries}, Fault in parsing: #{url}")
29
- sleep ||= @config['interval'].to_i
30
- retry if retries <= retry_max
31
- end
32
- }
33
- @return_feeds
20
+ Array(@config['urls']).each_with_object([]) do |url, feeds|
21
+ rss = fetch(url)
22
+ feeds << rss unless rss.nil?
23
+ end
34
24
  end
35
25
 
36
26
  private
37
27
 
38
- def create_rss(url)
39
- Automatic::Log.puts("info", "Parsing Link: #{url}")
40
- html = open(url).read
41
- unless html.nil?
42
- rss = Automatic::FeedParser.parse_html(html)
43
- sleep ||= @config['interval'].to_i
44
- @return_feeds << rss
28
+ def fetch(url)
29
+ retries = 0
30
+ retry_max = @config['retry'].to_i
31
+ begin
32
+ Automatic::Log.puts('info', "Parsing Link: #{url}")
33
+ rss = Automatic::FeedParser.parse_html(Automatic::Http.read(url))
34
+ sleep(@config['interval'].to_i)
35
+ rss
36
+ rescue StandardError => e
37
+ retries += 1
38
+ Automatic::Log.puts('error',
39
+ "ErrorCount: #{retries}, Fault in parsing: #{url}, #{e.message}")
40
+ return nil if retries > retry_max
41
+
42
+ sleep(@config['interval'].to_i)
43
+ retry
45
44
  end
46
45
  end
47
46
  end
@@ -1,67 +1,53 @@
1
1
  # -*- coding: utf-8 -*-
2
- # Name:: Automatic::Plugin::Subscription::Text
3
- # Author:: soramugi <http://soramugi.net>
4
- # 774 <http://id774.net>
5
- # Created:: May 6, 2013
6
- # Updated:: Feb 21, 2014
7
- # Copyright:: Copyright (c) 2012-2014 Automatic Ruby Developers.
8
- # License:: Licensed under the GNU GENERAL PUBLIC LICENSE, Version 3.0.
2
+ # Name:: Automatic::Plugin::Subscription::Text
3
+ # Author: soramugi (More info: http://soramugi.net)
4
+ # Source Code:: https://github.com/id774/automaticruby
5
+ # License:: The GPL version 3, or LGPL version 3 (Dual License).
6
+ # Contact:: idnanashi@gmail.com
7
+ # Created:: May 6, 2013
8
+ # Updated:: Aug 15, 2026
9
+ # Copyright:: Copyright (c) 2012-2026 Automatic Ruby Developers.
9
10
 
10
11
  module Automatic::Plugin
11
12
  class SubscriptionText
12
- def initialize(config, pipeline=[])
13
- @config = config
13
+ # Columns of a TSV row, in order. A row with fewer columns leaves the rest
14
+ # unset, which is what makes a one-column file of titles a valid input.
15
+ COLUMNS = %w[title url description author comments].freeze
16
+
17
+ def initialize(config, pipeline = [])
18
+ @config = config || {}
14
19
  @pipeline = pipeline
15
- @return_feeds = []
16
20
  end
17
21
 
22
+ # Reaches no network, which is what makes this the plugin to test a
23
+ # Recipe's later half with. Any combination of the four keys may be given.
18
24
  def run
19
- create_feed
20
- @pipeline << Automatic::FeedMaker.create_pipeline(@return_feeds) if @return_feeds.length > 0
25
+ items = titles + urls + feeds + files
26
+ @pipeline << Automatic::FeedMaker.create_pipeline(items) unless items.empty?
21
27
  @pipeline
22
28
  end
23
29
 
24
30
  private
25
31
 
26
- def create_feed
27
- unless @config.nil?
28
- @dummyfeeds = []
29
- unless @config['titles'].nil?
30
- @config['titles'].each {|title|
31
- feed = {}
32
- feed['title'] = title
33
- @return_feeds << Automatic::FeedMaker.generate_feed(feed)
34
- }
35
- end
32
+ def titles
33
+ Array(@config['titles']).map { |title| Automatic::FeedMaker.generate_feed('title' => title) }
34
+ end
36
35
 
37
- unless @config['urls'].nil?
38
- @config['urls'].each {|url|
39
- feed = {}
40
- feed['url'] = url
41
- @return_feeds << Automatic::FeedMaker.generate_feed(feed)
42
- }
43
- end
36
+ def urls
37
+ Array(@config['urls']).map { |url| Automatic::FeedMaker.generate_feed('url' => url) }
38
+ end
44
39
 
45
- unless @config['feeds'].nil?
46
- @config['feeds'].each {|feed|
47
- @return_feeds << Automatic::FeedMaker.generate_feed(feed)
48
- }
49
- end
40
+ def feeds
41
+ Array(@config['feeds']).map { |feed| Automatic::FeedMaker.generate_feed(feed) }
42
+ end
50
43
 
51
- unless @config['files'].nil?
52
- @config['files'].each {|f|
53
- open(File.expand_path(f)) do |file|
54
- file.each_line do |line|
55
- feed = {}
56
- feed['title'], feed['url'], feed['description'], feed['author'],
57
- feed['comments'] = line.force_encoding("utf-8").strip.split("\t")
58
- @return_feeds << Automatic::FeedMaker.generate_feed(feed)
59
- end
60
- end
61
- }
44
+ # Tab separated, read as UTF-8, and `~` expanded.
45
+ def files
46
+ Array(@config['files']).flat_map do |path|
47
+ File.foreach(File.expand_path(path), encoding: 'UTF-8').map do |line|
48
+ Automatic::FeedMaker.generate_feed(COLUMNS.zip(line.strip.split("\t")).to_h)
62
49
  end
63
50
  end
64
51
  end
65
-
66
52
  end
67
53
  end
@@ -1,59 +1,70 @@
1
1
  # -*- coding: utf-8 -*-
2
- # Name:: Automatic::Plugin::Subscription::Tumblr
3
- # Author:: 774 <http://id774.net>
4
- # Created:: Oct 16, 2012
5
- # Updated:: Feb 21, 2014
6
- # Copyright:: Copyright (c) 2012-2014 Automatic Ruby Developers.
7
- # License:: Licensed under the GNU GENERAL PUBLIC LICENSE, Version 3.0.
2
+ # Name:: Automatic::Plugin::Subscription::Tumblr
3
+ # Author: id774 (More info: http://id774.net)
4
+ # Source Code:: https://github.com/id774/automaticruby
5
+ # License:: The GPL version 3, or LGPL version 3 (Dual License).
6
+ # Contact:: idnanashi@gmail.com
7
+ # Created:: Oct 16, 2012
8
+ # Updated:: Aug 15, 2026
9
+ # Copyright:: Copyright (c) 2012-2026 Automatic Ruby Developers.
8
10
 
9
11
  module Automatic::Plugin
10
12
  class SubscriptionTumblr
11
- require 'open-uri'
12
-
13
- def initialize(config, pipeline=[])
14
- @config = config
13
+ def initialize(config, pipeline = [])
14
+ @config = config || {}
15
15
  @pipeline = pipeline
16
16
  end
17
17
 
18
+ # Reads HTML written for a browser, so what it finds depends on the theme
19
+ # a given blog uses. Verify against the blog you mean to follow before
20
+ # putting it in cron, and set `interval`.
18
21
  def run
19
- @return_feeds = []
20
- @config['urls'].each {|url|
21
- retries = 0
22
- retry_max = @config['retry'].to_i || 0
23
- begin
24
- create_rss(url)
25
- unless @config['pages'].nil?
26
- @config['pages'].times {|i|
27
- if i > 0
28
- old_url = url + "/page/" + (i+1).to_s
29
- create_rss(old_url)
30
- end
31
- }
32
- end
33
- rescue
34
- retries += 1
35
- Automatic::Log.puts("error", "ErrorCount: #{retries}, Fault in parsing: #{url}")
36
- sleep ||= @config['interval'].to_i
37
- retry if retries <= retry_max
22
+ Array(@config['urls']).each_with_object([]) do |url, feeds|
23
+ pages(url).each do |page|
24
+ rss = fetch(page, url)
25
+ feeds << rss unless rss.nil?
38
26
  end
39
- }
40
- @return_feeds
27
+ end
41
28
  end
42
29
 
43
30
  private
44
- def create_rss(url)
45
- Automatic::Log.puts("info", "Parsing Tumblr: #{url}")
46
- html = open(url).read
47
- unless html.nil?
48
- uri = URI.parse(url)
49
- rss = Automatic::FeedParser.parse_html(html)
50
- rss.items.each {|item|
51
- unless item.link =~ Regexp.new(uri.host)
52
- item.link = nil
53
- end
54
- }
55
- sleep ||= @config['interval'].to_i
56
- @return_feeds << rss
31
+
32
+ # The blog's own page, then /page/2 and onward.
33
+ def pages(url)
34
+ count = @config['pages'].to_i
35
+ return [url] if count < 2
36
+
37
+ [url] + (2..count).map { |number| "#{url}/page/#{number}" }
38
+ end
39
+
40
+ def fetch(url, blog_url)
41
+ retries = 0
42
+ retry_max = @config['retry'].to_i
43
+ begin
44
+ Automatic::Log.puts('info', "Parsing Tumblr: #{url}")
45
+ rss = Automatic::FeedParser.parse_html(Automatic::Http.read(url))
46
+ drop_offsite_links(rss, blog_url)
47
+ sleep(@config['interval'].to_i)
48
+ rss
49
+ rescue StandardError => e
50
+ retries += 1
51
+ Automatic::Log.puts('error',
52
+ "ErrorCount: #{retries}, Fault in parsing: #{url}, #{e.message}")
53
+ return nil if retries > retry_max
54
+
55
+ sleep(@config['interval'].to_i)
56
+ retry
57
+ end
58
+ end
59
+
60
+ # A theme's page carries the blog's own posts and a great deal else. A
61
+ # link that leaves the blog's host is blanked rather than removed, which
62
+ # is the pipeline's way of saying "not applicable"; the plugins after this
63
+ # one skip an item whose link is nil.
64
+ def drop_offsite_links(rss, blog_url)
65
+ host = Automatic::Http.uri(blog_url).host.to_s
66
+ rss.items.each do |item|
67
+ item.link = nil unless item.link.to_s.include?(host)
57
68
  end
58
69
  end
59
70
  end
@@ -1,53 +1,57 @@
1
1
  # -*- coding: utf-8 -*-
2
- # Name:: Automatic::Plugin::Subscription::Xml
3
- # Author:: 774 <http://id774.net>
4
- # Created:: Jul 12, 2013
5
- # Updated:: Oct 29, 2014
6
- # Copyright:: Copyright (c) 2012-2014 Automatic Ruby Developers.
7
- # License:: Licensed under the GNU GENERAL PUBLIC LICENSE, Version 3.0.
2
+ # Name:: Automatic::Plugin::Subscription::Xml
3
+ # Author: id774 (More info: http://id774.net)
4
+ # Source Code:: https://github.com/id774/automaticruby
5
+ # License:: The GPL version 3, or LGPL version 3 (Dual License).
6
+ # Contact:: idnanashi@gmail.com
7
+ # Created:: Jul 12, 2013
8
+ # Updated:: Aug 15, 2026
9
+ # Copyright:: Copyright (c) 2012-2026 Automatic Ruby Developers.
8
10
 
9
11
  module Automatic::Plugin
10
12
  class SubscriptionXml
11
- require 'open-uri'
12
- require 'active_support'
13
- require 'active_support/core_ext'
14
- require 'active_support/deprecation'
15
- require 'rss'
13
+ require 'active_support/core_ext/hash/conversions'
14
+ require 'json'
16
15
 
17
- def initialize(config, pipeline=[])
18
- @config = config
16
+ def initialize(config, pipeline = [])
17
+ @config = config || {}
19
18
  @pipeline = pipeline
20
19
  end
21
20
 
22
21
  def run
23
- @return_feeds = []
24
- @config['urls'].each {|url|
25
- retries = 0
26
- retry_max = @config['retry'].to_i || 0
27
- begin
28
- create_rss(URI::Parser.new.escape(url))
29
- rescue
30
- retries += 1
31
- Automatic::Log.puts("error", "ErrorCount: #{retries}, Fault in parsing: #{url}")
32
- sleep ||= @config['interval'].to_i
33
- retry if retries <= retry_max
34
- end
35
- }
36
- @return_feeds
22
+ Array(@config['urls']).each_with_object([]) do |url, feeds|
23
+ rss = fetch(url)
24
+ feeds << rss unless rss.nil?
25
+ end
37
26
  end
38
27
 
39
28
  private
40
29
 
41
- def create_rss(url)
42
- Automatic::Log.puts("info", "Parsing XML: #{url}")
43
- hash = Hash.from_xml(open(url).read)
44
- json = hash.to_json
45
- data = ActiveSupport::JSON.decode(json)
46
- unless data.nil?
47
- rss = Automatic::FeedMaker.content_provide(url, data)
48
- sleep ||= @config['interval'].to_i
49
- @return_feeds << rss
30
+ def fetch(url)
31
+ retries = 0
32
+ retry_max = @config['retry'].to_i
33
+ begin
34
+ Automatic::Log.puts('info', "Parsing XML: #{url}")
35
+ rss = Automatic::FeedMaker.content_provide(url, document(url))
36
+ sleep(@config['interval'].to_i)
37
+ rss
38
+ rescue StandardError => e
39
+ retries += 1
40
+ Automatic::Log.puts('error',
41
+ "ErrorCount: #{retries}, Fault in parsing: #{url}, #{e.message}")
42
+ return nil if retries > retry_max
43
+
44
+ sleep(@config['interval'].to_i)
45
+ retry
50
46
  end
51
47
  end
48
+
49
+ # The document as plain hashes, arrays and strings. The round trip through
50
+ # JSON is what flattens what Hash.from_xml returns -- dates, times and
51
+ # ActiveSupport's own string subclasses -- into the values a consumer such
52
+ # as ProvideFluentd can serialize.
53
+ def document(url)
54
+ JSON.parse(Hash.from_xml(Automatic::Http.read(url)).to_json)
55
+ end
52
56
  end
53
57
  end