automatic 12.2.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/Gemfile +23 -0
- data/README.md +109 -0
- data/Rakefile +42 -0
- data/VERSION +1 -0
- data/app.rb +15 -0
- data/automatic.gemspec +122 -0
- data/bin/automatic +15 -0
- data/config/default.yml +29 -0
- data/config/feed2console.yml +15 -0
- data/db/.gitkeep +0 -0
- data/doc/COPYING +674 -0
- data/doc/ChangeLog +17 -0
- data/doc/PLUGINS.ja +205 -0
- data/doc/README.ja +449 -0
- data/lib/automatic.rb +60 -0
- data/lib/automatic/environment.rb +8 -0
- data/lib/automatic/feed_parser.rb +36 -0
- data/lib/automatic/log.rb +24 -0
- data/lib/automatic/pipeline.rb +36 -0
- data/lib/automatic/recipe.rb +31 -0
- data/lib/config/validator.rb +83 -0
- data/plugins/custom_feed/svn_log.rb +56 -0
- data/plugins/filter/ignore.rb +60 -0
- data/plugins/filter/image.rb +47 -0
- data/plugins/filter/tumblr_resize.rb +40 -0
- data/plugins/notify/ikachan.rb +85 -0
- data/plugins/publish/console.rb +31 -0
- data/plugins/publish/google_calendar.rb +86 -0
- data/plugins/publish/hatena_bookmark.rb +103 -0
- data/plugins/store/full_text.rb +57 -0
- data/plugins/store/permalink.rb +47 -0
- data/plugins/store/store_database.rb +53 -0
- data/plugins/store/target_link.rb +47 -0
- data/plugins/subscription/feed.rb +30 -0
- data/script/bootstrap +117 -0
- data/spec/plugins/custom_feed/svn_log_spec.rb +31 -0
- data/spec/plugins/filter/ignore_spec.rb +37 -0
- data/spec/plugins/filter/image_spec.rb +55 -0
- data/spec/plugins/filter/tumblr_resize_spec.rb +102 -0
- data/spec/plugins/notify/ikachan_spec.rb +28 -0
- data/spec/plugins/publish/console_spec.rb +24 -0
- data/spec/plugins/publish/google_calendar_spec.rb +82 -0
- data/spec/plugins/publish/hatena_bookmark_spec.rb +36 -0
- data/spec/plugins/store/full_text_spec.rb +39 -0
- data/spec/plugins/store/permalink_spec.rb +39 -0
- data/spec/plugins/store/target_link_spec.rb +30 -0
- data/spec/plugins/subscription/feed_spec.rb +36 -0
- data/spec/spec_helper.rb +82 -0
- data/test/integration/test_activerecord.yml +24 -0
- data/test/integration/test_fulltext.yml +24 -0
- data/test/integration/test_hatenabookmark.yml +26 -0
- data/test/integration/test_ignore.yml +22 -0
- data/test/integration/test_ignore2.yml +25 -0
- data/test/integration/test_image2local.yml +26 -0
- data/test/integration/test_svnlog.yml +14 -0
- data/test/integration/test_tumblr2local.yml +26 -0
- data/utils/auto_discovery.rb +18 -0
- data/utils/opml_parser.rb +247 -0
- data/vendor/.gitkeep +0 -0
- metadata +205 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '../../../spec_helper')
|
2
|
+
|
3
|
+
require 'notify/ikachan'
|
4
|
+
|
5
|
+
describe Automatic::Plugin::NotifyIkachan do
|
6
|
+
paramz = {
|
7
|
+
"channels" => "#room",
|
8
|
+
"url" => "http://sample.com",
|
9
|
+
"port" => "4979",
|
10
|
+
"command" => "notice",
|
11
|
+
}
|
12
|
+
subject {
|
13
|
+
Automatic::Plugin::NotifyIkachan.new(
|
14
|
+
paramz,
|
15
|
+
AutomaticSpec.generate_pipeline {
|
16
|
+
feed { item "http://github.com", "GitHub" }
|
17
|
+
}
|
18
|
+
)
|
19
|
+
}
|
20
|
+
|
21
|
+
it "should post title and link in the feed" do
|
22
|
+
ikachan = mock("ikachan")
|
23
|
+
ikachan.should_receive(:post).with("http://github.com", "GitHub")
|
24
|
+
ikachan.should_receive(:params)
|
25
|
+
subject.instance_variable_set(:@ikachan, ikachan)
|
26
|
+
subject.run.should have(1).feed
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '../../../spec_helper')
|
2
|
+
|
3
|
+
require 'publish/console'
|
4
|
+
|
5
|
+
describe Automatic::Plugin::PublishConsole do
|
6
|
+
before do
|
7
|
+
@pipeline = AutomaticSpec.generate_pipeline {
|
8
|
+
feed { item "http://github.com" }
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
subject {
|
13
|
+
Automatic::Plugin::PublishConsole.new({}, @pipeline)
|
14
|
+
}
|
15
|
+
|
16
|
+
it "should output pretty inspect of feeds" do
|
17
|
+
output = mock("output")
|
18
|
+
output.should_receive(:puts).
|
19
|
+
with("info", @pipeline[0].items[0].pretty_inspect)
|
20
|
+
subject.instance_variable_set(:@output, output)
|
21
|
+
subject.run
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Name:: Automatic::Plugin::CustomFeed::SVNFLog
|
3
|
+
# Author:: kzgs
|
4
|
+
# Created:: Feb 26, 2012
|
5
|
+
# Updated:: Mar 3, 2012
|
6
|
+
# Copyright:: kzgs Copyright (c) 2012
|
7
|
+
# License:: Licensed under the GNU GENERAL PUBLIC LICENSE, Version 3.0.
|
8
|
+
|
9
|
+
require File.expand_path(File.dirname(__FILE__) + '../../../spec_helper')
|
10
|
+
|
11
|
+
require 'publish/google_calendar'
|
12
|
+
require 'gcalapi'
|
13
|
+
|
14
|
+
describe Automatic::Plugin::PublishGoogleCalendar do
|
15
|
+
subject {
|
16
|
+
Automatic::Plugin::PublishGoogleCalendar.new(
|
17
|
+
{"username" => "user", "password" => "pswd"},
|
18
|
+
AutomaticSpec.generate_pipeline{
|
19
|
+
feed {
|
20
|
+
item "http://github.com", "GitHub"
|
21
|
+
}
|
22
|
+
})
|
23
|
+
}
|
24
|
+
|
25
|
+
it "should post the link in the feed" do
|
26
|
+
gc = mock("gc")
|
27
|
+
gc.should_receive(:add).with("今日 GitHub")
|
28
|
+
subject.instance_variable_set(:@gc, gc)
|
29
|
+
subject.run.should have(1).feed
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe Automatic::Plugin::Googlecalendar do
|
34
|
+
describe "#add" do
|
35
|
+
context "All day events" do
|
36
|
+
specify {
|
37
|
+
set_gcal_mock(all_day_event_mock(
|
38
|
+
"花火@晴海", "", Time.mktime(2012, 8, 15)))
|
39
|
+
Automatic::Plugin::Googlecalendar.new.add("2012/8/15 花火@晴海")
|
40
|
+
}
|
41
|
+
|
42
|
+
specify {
|
43
|
+
lambda {
|
44
|
+
Automatic::Plugin::Googlecalendar.new.add("2012/2/30")
|
45
|
+
}.should raise_exception(RuntimeError, /不正な日付形式-1/)
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def all_day_event_mock(title, where, date=nil)
|
52
|
+
event = mock("event")
|
53
|
+
{
|
54
|
+
:title => title,
|
55
|
+
:st => date.nil? ? nil : Time.mktime(date.year, date.month, date.day),
|
56
|
+
:en => nil,
|
57
|
+
:allday => true
|
58
|
+
}.each_pair do |key, value|
|
59
|
+
if value.nil?
|
60
|
+
event.should_receive("#{key}=".to_sym)
|
61
|
+
else
|
62
|
+
event.should_receive("#{key}=".to_sym).with(value)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
event.should_receive(:st)
|
66
|
+
event.should_receive(:save!)
|
67
|
+
return event
|
68
|
+
end
|
69
|
+
|
70
|
+
def cal_mock(event_mock)
|
71
|
+
cal = mock("cal")
|
72
|
+
cal.should_receive(:create_event).and_return {
|
73
|
+
event_mock
|
74
|
+
}
|
75
|
+
return cal
|
76
|
+
end
|
77
|
+
|
78
|
+
def set_gcal_mock(event_mock)
|
79
|
+
GoogleCalendar::Calendar.stub(:new) {
|
80
|
+
cal_mock(event_mock)
|
81
|
+
}
|
82
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '../../../spec_helper')
|
2
|
+
|
3
|
+
require 'publish/hatena_bookmark'
|
4
|
+
|
5
|
+
describe Automatic::Plugin::PublishHatenaBookmark do
|
6
|
+
subject {
|
7
|
+
Automatic::Plugin::PublishHatenaBookmark.new(
|
8
|
+
{"username" => "user", "password" => "pswd"},
|
9
|
+
AutomaticSpec.generate_pipeline{
|
10
|
+
feed { item "http://github.com" }
|
11
|
+
})
|
12
|
+
}
|
13
|
+
|
14
|
+
it "should post the link in the feed" do
|
15
|
+
hb = mock("hb")
|
16
|
+
hb.should_receive(:post).with("http://github.com", nil)
|
17
|
+
subject.instance_variable_set(:@hb, hb)
|
18
|
+
subject.run.should have(1).feed
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe Automatic::Plugin::HatenaBookmark do
|
23
|
+
describe "#wsse" do
|
24
|
+
subject {
|
25
|
+
Automatic::Plugin::HatenaBookmark.new.wsse("anonymous", "pswd")
|
26
|
+
}
|
27
|
+
|
28
|
+
it { should be_has_key('X-WSSE') }
|
29
|
+
|
30
|
+
specify {
|
31
|
+
subject['X-WSSE'].should match(
|
32
|
+
/^UsernameToken\sUsername="anonymous",\sPasswordDigest=".+", Nonce=".+", Created="\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z"/)
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '../../../spec_helper')
|
3
|
+
|
4
|
+
require 'store/full_text'
|
5
|
+
|
6
|
+
require 'pathname'
|
7
|
+
|
8
|
+
describe Automatic::Plugin::StoreFullText do
|
9
|
+
before do
|
10
|
+
@db_filename = "test_full_text.db"
|
11
|
+
db_path = Pathname(AutomaticSpec.db_dir).cleanpath+"#{@db_filename}"
|
12
|
+
db_path.delete if db_path.exist?
|
13
|
+
Automatic::Plugin::StoreFullText.new({"db" => @db_filename}).run
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should store 1 record for the new blog entry" do
|
17
|
+
instance = Automatic::Plugin::StoreFullText.new({"db" => @db_filename},
|
18
|
+
AutomaticSpec.generate_pipeline {
|
19
|
+
feed { item "http://id774.net/blog/feed/" }
|
20
|
+
})
|
21
|
+
|
22
|
+
lambda {
|
23
|
+
instance.run.should have(1).feed
|
24
|
+
}.should change(Automatic::Plugin::Blog, :count).by(1)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should not store record for the existent blog entry" do
|
28
|
+
instance = Automatic::Plugin::StoreFullText.new({"db" => @db_filename},
|
29
|
+
AutomaticSpec.generate_pipeline {
|
30
|
+
feed { item "http://id774.net/blog/feed/" }
|
31
|
+
})
|
32
|
+
|
33
|
+
instance.run.should have(1).feed
|
34
|
+
lambda {
|
35
|
+
instance.run.should have(0).feed
|
36
|
+
}.should change(Automatic::Plugin::Blog, :count).by(0)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '../../../spec_helper')
|
3
|
+
|
4
|
+
require 'store/permalink'
|
5
|
+
|
6
|
+
require 'pathname'
|
7
|
+
|
8
|
+
describe Automatic::Plugin::StorePermalink do
|
9
|
+
before do
|
10
|
+
@db_filename = "test_permalink.db"
|
11
|
+
db_path = Pathname(AutomaticSpec.db_dir).cleanpath+"#{@db_filename}"
|
12
|
+
db_path.delete if db_path.exist?
|
13
|
+
Automatic::Plugin::StorePermalink.new({"db" => @db_filename}).run
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should store 1 record for the new link" do
|
17
|
+
instance = Automatic::Plugin::StorePermalink.new({"db" => @db_filename},
|
18
|
+
AutomaticSpec.generate_pipeline {
|
19
|
+
feed { item "http://github.com" }
|
20
|
+
})
|
21
|
+
|
22
|
+
lambda {
|
23
|
+
instance.run.should have(1).feed
|
24
|
+
}.should change(Automatic::Plugin::Permalink, :count).by(1)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should not store record for the existent link" do
|
28
|
+
instance = Automatic::Plugin::StorePermalink.new({"db" => @db_filename},
|
29
|
+
AutomaticSpec.generate_pipeline {
|
30
|
+
feed { item "http://github.com" }
|
31
|
+
})
|
32
|
+
|
33
|
+
instance.run.should have(1).feed
|
34
|
+
lambda {
|
35
|
+
instance.run.should have(0).feed
|
36
|
+
}.should change(Automatic::Plugin::Permalink, :count).by(0)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Name:: Automatic::Plugin::CustomFeed::SVNFLog
|
3
|
+
# Author:: kzgs
|
4
|
+
# Created:: Mar 4, 2012
|
5
|
+
# Updated:: Mar 4, 2012
|
6
|
+
# Copyright:: kzgs Copyright (c) 2012
|
7
|
+
# License:: Licensed under the GNU GENERAL PUBLIC LICENSE, Version 3.0.
|
8
|
+
|
9
|
+
require File.expand_path(File.dirname(__FILE__) + '../../../spec_helper')
|
10
|
+
|
11
|
+
require 'store/target_link'
|
12
|
+
|
13
|
+
require 'tmpdir'
|
14
|
+
require 'pathname'
|
15
|
+
|
16
|
+
describe Automatic::Plugin::StoreTargetLink do
|
17
|
+
it "should store the target link" do
|
18
|
+
Dir.mktmpdir do |dir|
|
19
|
+
instance = Automatic::Plugin::StoreTargetLink.new(
|
20
|
+
{ "path" => dir },
|
21
|
+
AutomaticSpec.generate_pipeline {
|
22
|
+
feed { item "http://digithoughts.com/rss" }
|
23
|
+
})
|
24
|
+
|
25
|
+
instance.run.should have(1).feed
|
26
|
+
(Pathname(dir)+"rss").should be_exist
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '../../../spec_helper')
|
2
|
+
|
3
|
+
require 'subscription/feed'
|
4
|
+
|
5
|
+
describe Automatic::Plugin::SubscriptionFeed do
|
6
|
+
context "with empty feeds" do
|
7
|
+
subject {
|
8
|
+
Automatic::Plugin::SubscriptionFeed.new(
|
9
|
+
{ 'feeds' => [] })
|
10
|
+
}
|
11
|
+
|
12
|
+
its(:run) { should be_empty }
|
13
|
+
end
|
14
|
+
|
15
|
+
context "with feeds whose invalid URL" do
|
16
|
+
subject {
|
17
|
+
Automatic::Plugin::SubscriptionFeed.new(
|
18
|
+
{ 'feeds' => ["invalid_url"] })
|
19
|
+
}
|
20
|
+
|
21
|
+
its(:run) { should be_empty }
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
context "with feeds whose valid URL" do
|
26
|
+
subject {
|
27
|
+
Automatic::Plugin::SubscriptionFeed.new(
|
28
|
+
{ 'feeds' => [
|
29
|
+
"https://github.com/id774/automaticruby/commits/master.atom"]
|
30
|
+
})
|
31
|
+
}
|
32
|
+
|
33
|
+
its(:run) { should have(1).feed }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'plugins'))
|
3
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
4
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..'))
|
5
|
+
|
6
|
+
Bundler.require :test if defined?(Bundler)
|
7
|
+
|
8
|
+
if ENV['COVERAGE'] == 'on'
|
9
|
+
require 'simplecov'
|
10
|
+
require 'simplecov-rcov'
|
11
|
+
SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter
|
12
|
+
|
13
|
+
SimpleCov.start do
|
14
|
+
add_filter "spec"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
require 'lib/automatic'
|
19
|
+
|
20
|
+
# Requires supporting files with custom matchers and macros, etc,
|
21
|
+
# in ./support/ and its subdirectories.
|
22
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
23
|
+
|
24
|
+
unless /^1\.9\./ =~ RUBY_VERSION
|
25
|
+
require 'rspec'
|
26
|
+
end
|
27
|
+
|
28
|
+
RSpec.configure do |config|
|
29
|
+
config.mock_with :rspec
|
30
|
+
end
|
31
|
+
|
32
|
+
module AutomaticSpec
|
33
|
+
class << self
|
34
|
+
def generate_pipeline(&block)
|
35
|
+
pipeline_generator = StubPipelineGenerator.new
|
36
|
+
pipeline_generator.instance_eval(&block)
|
37
|
+
return pipeline_generator.feeds
|
38
|
+
end
|
39
|
+
|
40
|
+
def root_dir
|
41
|
+
return File.join(__FILE__, "../../")
|
42
|
+
end
|
43
|
+
|
44
|
+
def db_dir
|
45
|
+
return File.join(root_dir, "db")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class StubPipelineGenerator
|
50
|
+
attr_reader :feeds
|
51
|
+
|
52
|
+
def initialize
|
53
|
+
@feeds = []
|
54
|
+
end
|
55
|
+
|
56
|
+
def feed(&block)
|
57
|
+
feed_generator = StubFeedGenerator.new
|
58
|
+
feed_generator.instance_eval(&block)
|
59
|
+
@feeds << feed_generator.feed
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class StubFeedGenerator
|
64
|
+
def initialize
|
65
|
+
@channel = RSS::Rss::Channel.new
|
66
|
+
end
|
67
|
+
|
68
|
+
def feed
|
69
|
+
rss = RSS::Rss.new([])
|
70
|
+
rss.instance_variable_set(:@channel, @channel)
|
71
|
+
return rss
|
72
|
+
end
|
73
|
+
|
74
|
+
def item(url, title="", description="")
|
75
|
+
itm = RSS::Rss::Channel::Item.new
|
76
|
+
itm.link = url
|
77
|
+
itm.title = title unless title.blank?
|
78
|
+
itm.instance_variable_set(:@description, description)
|
79
|
+
@channel.items << itm
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
global:
|
2
|
+
timezone: Asia/Tokyo
|
3
|
+
cache:
|
4
|
+
base: /tmp
|
5
|
+
log:
|
6
|
+
level: info
|
7
|
+
|
8
|
+
plugins:
|
9
|
+
- module: SubscriptionFeed
|
10
|
+
config:
|
11
|
+
feeds:
|
12
|
+
- http://id774.net/blog/feed/
|
13
|
+
|
14
|
+
- module: FilterIgnore
|
15
|
+
config:
|
16
|
+
exclude:
|
17
|
+
- hoge
|
18
|
+
|
19
|
+
- module: StorePermalink
|
20
|
+
config:
|
21
|
+
db: test_permalink.db
|
22
|
+
|
23
|
+
- module: PublishConsole
|
24
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
global:
|
2
|
+
timezone: Asia/Tokyo
|
3
|
+
cache:
|
4
|
+
base: /tmp
|
5
|
+
log:
|
6
|
+
level: info
|
7
|
+
|
8
|
+
plugins:
|
9
|
+
- module: SubscriptionFeed
|
10
|
+
config:
|
11
|
+
feeds:
|
12
|
+
- http://id774.net/blog/feed/
|
13
|
+
|
14
|
+
- module: FilterIgnore
|
15
|
+
config:
|
16
|
+
exclude:
|
17
|
+
- hoge
|
18
|
+
|
19
|
+
- module: PublishConsole
|
20
|
+
|
21
|
+
- module: StoreFullText
|
22
|
+
config:
|
23
|
+
db: blog.db
|
24
|
+
|