akane 0.2.0 → 0.3.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: de30517cd16b9dd52bf5628602e20e22dfcb594a
4
- data.tar.gz: 509875d93f4c1bcebfb950f289b206d69916f2ea
3
+ metadata.gz: 8bc71995c8cc299ddc5b873403f69f427ab87f6d
4
+ data.tar.gz: cdffc166e5a090a3159c60e3e2507b51d4eac98c
5
5
  SHA512:
6
- metadata.gz: 98ec5786e6587eac236b868309b85fc9a8d1fc445b761f927e1085c04629fb7534105bee28bec99796af86b7aa2ba44ea9e87fb5f6a738370b5ca97e36a91038
7
- data.tar.gz: 3c6ab75d276a089ce1a0486dfb608c3a09f029ece9096a94a98caf2927447ef275c9f64338e7f707ae96dd273da997b18e0d1b9cea35935e4d8e59c6720c4d2a
6
+ metadata.gz: 74c163daa0604773c155a7828f9417605ba200e9f041a91d879855cb3c5784a0bff53c25cbca4f10b7a39fa3c5334f39fdf8f463dc46f9c21484ca1d5dab763e
7
+ data.tar.gz: c75dde351210dfbec90073c72aa1c7c75320538e398d0c4232729b811936c2b9e89e074d594e8522fdcd278f6c39f2ae90419fa0303aaaaa7fd70a01119c5840
data/README.md CHANGED
@@ -10,9 +10,15 @@ Log your timeline
10
10
 
11
11
  $ gem install akane
12
12
 
13
- ## Usage
13
+ ## Set up
14
14
 
15
- TBD
15
+ See `akane.example.yml`
16
+
17
+ ## Start
18
+
19
+ ```
20
+ $ akane start -c /path/to/akane.yml
21
+ ```
16
22
 
17
23
  ## Todo
18
24
 
data/akane.example.yml CHANGED
@@ -2,13 +2,24 @@
2
2
  consumer:
3
3
  token: CONSUMER_TOKEN
4
4
  secret: CONSUMER_SECRET
5
+
6
+ # You can issue access tokens for accounts by using `akane auth` command.
5
7
  accounts:
6
8
  your_account_name1:
7
9
  token: ACCESS_TOKEN1
8
10
  secret: SECRET_TOKEN1
11
+ # You can specify custom receivers for each account.
12
+ # by default, `receivers: ["stream"]` will be used.
13
+ # receivers:
14
+ # - stream
15
+ # - stream:
16
+ # method: filter
17
+ # options:
18
+ # track: foo,bar,baz
9
19
  your_account_name2:
10
20
  token: ACCESS_TOKEN2
11
21
  secret: SECRET_TOKEN2
22
+
12
23
  storages:
13
24
  - stdout
14
25
  - file:
data/lib/akane/manager.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'akane/config'
2
2
  require 'akane/recorder'
3
- require 'akane/receivers/stream'
3
+ require 'akane/receivers'
4
+ require 'akane/storages'
4
5
 
5
6
  module Akane
6
7
  class Manager
@@ -11,43 +12,10 @@ module Akane
11
12
 
12
13
  def prepare
13
14
  @logger.info 'Preparing'
14
- @receivers = @config["accounts"].map do |name, credential|
15
- Akane::Receivers::Stream.new(
16
- consumer: {token: @config["consumer"]["token"], secret: @config["consumer"]["secret"]},
17
- account: {token: credential["token"], secret: credential["secret"]},
18
- logger: @config.logger
19
- ).tap do |receiver|
20
- @logger.info "Preparing... receiver - #{receiver.class}"
21
- receiver.on_tweet( &(method(:on_tweet).to_proc.curry[name]))
22
- receiver.on_message(&(method(:on_message).to_proc.curry[name]))
23
- receiver.on_event( &(method(:on_event).to_proc.curry[name]))
24
- receiver.on_delete( &(method(:on_delete).to_proc.curry[name]))
25
- end
26
- end
27
15
 
28
- @storages = @config["storages"].flat_map do |definition|
29
- case definition
30
- when Hash
31
- definition.map do |kind, config|
32
- [kind, config]
33
- end
34
- when String
35
- [[definition, {}]]
36
- end
37
- end.map do |kind, config|
38
- @logger.info "Preparing... storage - #{kind}"
39
- require "akane/storages/#{kind}"
40
- Akane::Storages.const_get(kind.gsub(/(?:\A|_)(.)/) { $1.upcase }).new(
41
- config: config,
42
- logger: @config.logger
43
- )
44
- end
45
-
46
- @recorder = Akane::Recorder.new(
47
- @storages,
48
- timeout: @config["timeout"] || 20,
49
- logger: @config.logger
50
- )
16
+ prepare_receivers
17
+ prepare_storages
18
+ prepare_recorder
51
19
 
52
20
  @logger.info "Prepared with #{@storages.size} storage(s) and #{@receivers.size} receiver(s)"
53
21
  end
@@ -129,5 +97,63 @@ module Akane
129
97
  def on_delete(account, user_id, tweet_id)
130
98
  @recorder.mark_as_deleted(account, user_id, tweet_id)
131
99
  end
100
+
101
+ def prepare_receivers
102
+ @receivers = @config["accounts"].flat_map do |name, credential|
103
+ receiver_definitions = credential["receivers"] || ['stream']
104
+
105
+ receiver_definitions.map do |definition|
106
+ if definition.kind_of?(Hash)
107
+ if 1 < definition.size
108
+ @logger.warn "Only 1 receiver definition is used in one Hash instance."
109
+ end
110
+
111
+ kind, config = definition.each.first
112
+ else
113
+ kind, config = definition, {}
114
+ end
115
+
116
+ Akane::Receivers.find(kind).new(
117
+ consumer: {token: @config["consumer"]["token"], secret: @config["consumer"]["secret"]},
118
+ account: {token: credential["token"], secret: credential["secret"], name: name},
119
+ config: config,
120
+ logger: @config.logger
121
+ ).tap do |receiver|
122
+ @logger.info "Preparing... receiver - #{receiver.class}"
123
+ receiver.on_tweet(&( method(:on_tweet).to_proc.curry[receiver.name]))
124
+ receiver.on_message(&(method(:on_message).to_proc.curry[receiver.name]))
125
+ receiver.on_event(&( method(:on_event).to_proc.curry[receiver.name]))
126
+ receiver.on_delete(&( method(:on_delete).to_proc.curry[receiver.name]))
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+ def prepare_storages
133
+ @storages = @config["storages"].flat_map do |definition|
134
+ case definition
135
+ when Hash
136
+ definition.map do |kind, config|
137
+ [kind, config]
138
+ end
139
+ when String
140
+ [[definition, {}]]
141
+ end
142
+ end.map do |kind, config|
143
+ @logger.info "Preparing... storage - #{kind}"
144
+ Akane::Storages.find(kind).new(
145
+ config: config,
146
+ logger: @config.logger
147
+ )
148
+ end
149
+ end
150
+
151
+ def prepare_recorder
152
+ @recorder = Akane::Recorder.new(
153
+ @storages,
154
+ timeout: @config["timeout"] || 20,
155
+ logger: @config.logger
156
+ )
157
+ end
132
158
  end
133
159
  end
@@ -0,0 +1,17 @@
1
+ module Akane
2
+ module Receivers
3
+ def self.find(name)
4
+ class_name = name.gsub(/(?:\A|_)(.)/) { $1.upcase }
5
+
6
+ retried = false
7
+ begin
8
+ return Akane::Receivers.const_get(class_name, false)
9
+ rescue NameError => e
10
+ raise e if retried
11
+ retried = true
12
+ require "akane/receivers/#{name}"
13
+ retry
14
+ end
15
+ end
16
+ end
17
+ end
@@ -4,6 +4,7 @@ module Akane
4
4
  def initialize(consumer: raise(ArgumentError, 'missing consumer'),
5
5
  account: raise(ArgumentError, 'missing account'),
6
6
  logger: Logger.new($stdout),
7
+ name: nil,
7
8
  config: {})
8
9
  @consumer = consumer
9
10
  @account = account
@@ -13,6 +14,10 @@ module Akane
13
14
  @hooks = {}
14
15
  end
15
16
 
17
+ def name
18
+ @name ||= @config['name'] || "#{cname}:#{@account[:name]}"
19
+ end
20
+
16
21
  def start
17
22
  raise NotImplementedError
18
23
  end
@@ -37,6 +42,10 @@ module Akane
37
42
 
38
43
  private
39
44
 
45
+ def cname
46
+ @cname = self.class.name.split(/::/).last
47
+ end
48
+
40
49
  def invoke(kind, *args)
41
50
  return unless @hooks[kind]
42
51
  @hooks[kind].each { |hook| hook.call(*args) }
@@ -7,6 +7,26 @@ module Akane
7
7
  def initialize(*)
8
8
  super
9
9
  @thread = nil
10
+
11
+ if @config["method"]
12
+ @stream_method = @config["method"].to_sym
13
+ else
14
+ @stream_method = :user
15
+ end
16
+
17
+ if @config["options"]
18
+ @stream_options = Hash[@config["options"].map do |k,v|
19
+ [k.to_sym, v]
20
+ end]
21
+ else
22
+ @stream_options = {}
23
+ end
24
+ end
25
+
26
+ def name
27
+ # For backward compatibility, user stream returns only account name if
28
+ # config.name not specified.
29
+ @name ||= @config['name'] || @account[:name]
10
30
  end
11
31
 
12
32
  def running?() !!(@thread && @thread.alive?) end
@@ -27,7 +47,7 @@ module Akane
27
47
 
28
48
  @thread = Thread.new do
29
49
  begin
30
- stream.user do |obj|
50
+ stream.send(@stream_method, @stream_options) do |obj|
31
51
  case obj
32
52
  when Twitter::Tweet
33
53
  invoke(:tweet, obj)
@@ -0,0 +1,17 @@
1
+ module Akane
2
+ module Storages
3
+ def self.find(name)
4
+ class_name = name.gsub(/(?:\A|_)(.)/) { $1.upcase }
5
+
6
+ retried = false
7
+ begin
8
+ return Akane::Storages.const_get(class_name, false)
9
+ rescue NameError => e
10
+ raise e if retried
11
+ retried = true
12
+ require "akane/storages/#{name}"
13
+ retry
14
+ end
15
+ end
16
+ end
17
+ end
data/lib/akane/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Akane
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
data/spec/manager_spec.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'akane/manager'
3
3
  require 'akane/receivers/stream'
4
+ require 'akane/receivers/abstract_receiver'
4
5
  require 'akane/storages/mock'
5
6
  require 'akane/config'
6
7
 
@@ -35,7 +36,8 @@ describe Akane::Manager do
35
36
  it "creates receivers" do
36
37
  Akane::Receivers::Stream.should_receive(:new) \
37
38
  .with(consumer: {token: 'consumer-token', secret: 'consumer-secret'},
38
- account: {token: 'a-access-token', secret: 'a-access-secret'},
39
+ account: {token: 'a-access-token', secret: 'a-access-secret', name: 'a'},
40
+ config: {},
39
41
  logger: config.logger) \
40
42
  .and_return(double("a").as_null_object)
41
43
 
@@ -54,6 +56,58 @@ describe Akane::Manager do
54
56
 
55
57
  subject.prepare
56
58
  end
59
+
60
+ context "with config.accounts[].receivers" do
61
+ let(:conf_accounts) do
62
+ {
63
+ "a" => {
64
+ "token" => "a-access-token",
65
+ "secret" => "a-access-secret",
66
+ "receivers" => [
67
+ 'foo',
68
+ {"bar" => {'hello' => 'hola',}},
69
+ ],
70
+ },
71
+ "b" => {
72
+ "token" => "b-access-token",
73
+ "secret" => "b-access-secret",
74
+ },
75
+ }
76
+ end
77
+
78
+ let(:foo_receiver) { Class.new(Akane::Receivers::AbstractReceiver) {} }
79
+ let(:bar_receiver) { Class.new(Akane::Receivers::AbstractReceiver) {} }
80
+
81
+ before do
82
+ stub_const 'Akane::Receivers::Foo', foo_receiver
83
+ stub_const 'Akane::Receivers::Bar', bar_receiver
84
+ end
85
+
86
+ it "creates receivers" do
87
+ expect(foo_receiver).to receive(:new) \
88
+ .with(consumer: {token: 'consumer-token', secret: 'consumer-secret'},
89
+ account: {token: 'a-access-token', secret: 'a-access-secret', name: 'a'},
90
+ config: {},
91
+ logger: config.logger) \
92
+ .and_return(double("foo").as_null_object)
93
+
94
+ expect(bar_receiver).to receive(:new) \
95
+ .with(consumer: {token: 'consumer-token', secret: 'consumer-secret'},
96
+ account: {token: 'a-access-token', secret: 'a-access-secret', name: 'a'},
97
+ config: {'hello' => 'hola',},
98
+ logger: config.logger) \
99
+ .and_return(double("bar").as_null_object)
100
+
101
+ Akane::Receivers::Stream.should_receive(:new) \
102
+ .with(consumer: {token: 'consumer-token', secret: 'consumer-secret'},
103
+ account: {token: 'b-access-token', secret: 'b-access-secret', name: 'b'},
104
+ config: {},
105
+ logger: config.logger) \
106
+ .and_return(double("bstream").as_null_object)
107
+
108
+ subject.prepare
109
+ end
110
+ end
57
111
  end
58
112
 
59
113
  describe "#start" do
@@ -64,6 +118,7 @@ describe Akane::Manager do
64
118
  Akane::Recorder.stub(new: recorder)
65
119
 
66
120
  @on_event, @on_tweet, @on_delete, @on_message = nil
121
+ receiver.stub(name: 'a')
67
122
  receiver.stub(:on_event) { |&block| @on_event = block }
68
123
  receiver.stub(:on_tweet) { |&block| @on_tweet = block }
69
124
  receiver.stub(:on_delete) { |&block| @on_delete = block }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: akane
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shota Fukumori (sora_h)
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-06 00:00:00.000000000 Z
11
+ date: 2014-08-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: elasticsearch
@@ -143,9 +143,11 @@ files:
143
143
  - lib/akane/cli.rb
144
144
  - lib/akane/config.rb
145
145
  - lib/akane/manager.rb
146
+ - lib/akane/receivers.rb
146
147
  - lib/akane/receivers/abstract_receiver.rb
147
148
  - lib/akane/receivers/stream.rb
148
149
  - lib/akane/recorder.rb
150
+ - lib/akane/storages.rb
149
151
  - lib/akane/storages/abstract_storage.rb
150
152
  - lib/akane/storages/elasticsearch.rb
151
153
  - lib/akane/storages/file.rb