automatic 12.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|