akane 0.0.1 → 0.1.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: da68e17edf6170994c230591963faaa2f127ce0a
4
- data.tar.gz: 112e4fd65c01fbd1bc45c5bf35fab09824482e42
3
+ metadata.gz: 0bd862e8bde263f78e295317635f8bb4eb0256cd
4
+ data.tar.gz: 4b64ada85e74c5018bc7f013c3f37d850cccb7e5
5
5
  SHA512:
6
- metadata.gz: 4029d0d629134c6b7e27bafdcfc72747ef7ae104b97a4c303b2175278384c298b6b993169442f2fabe76aa57c322f5438e0f88b1c2e657127da78fb273a86833
7
- data.tar.gz: 60e2d7f0b8387798df35547b334e1e8b9dc40300f3c6a05455cbaa0d4f86dff0d201654477e741b1fb346dcf137d6fa18e2fab08daa2b662e9551e4315b75766
6
+ metadata.gz: 2015deae33ec6b5598a17743dc308f01ce8cf452819f1f2ca2334b1a37365897fb79c7f7d8676bb1618ebe5bc9ac98d3e224d39cd34738bad89cecb038029343
7
+ data.tar.gz: fe3250c3bc69de4bafcad0f68ea3d488efdf0ee75d7718e04eabe27f3ce2a400a200fab02bb1fe124858dab17d430fa2555277278b38cf161ae38696e4f681da
data/akane.gemspec CHANGED
@@ -18,8 +18,9 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency "tweetstream", "~> 2.6.0"
22
21
  spec.add_dependency "elasticsearch", "~> 0.4.1"
22
+ spec.add_dependency "twitter", "~> 5.5.1"
23
+ spec.add_dependency "oauth", ">= 0.4.7"
23
24
 
24
25
  spec.add_development_dependency "bundler"
25
26
  spec.add_development_dependency "rake"
data/lib/akane/cli.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'akane/manager'
2
2
  require 'akane/config'
3
+ require 'optparse'
3
4
 
4
5
  module Akane
5
6
  class CLI
@@ -20,6 +21,35 @@ module Akane
20
21
  manager.run
21
22
  end
22
23
 
24
+ def auth
25
+ require 'twitter'
26
+
27
+ consumer = config.consumer
28
+
29
+ request_token = consumer.get_request_token
30
+ puts "Allow me using this URL: #{request_token.authorize_url}"
31
+ print "Then type shown PIN: "
32
+ pin = $stdin.gets.chomp
33
+ print "Authorizing... "
34
+
35
+ access_token = request_token.get_access_token(oauth_verifier: pin)
36
+ twitter = Twitter::REST::Client.new(
37
+ consumer_key: config[:consumer]['token'],
38
+ consumer_secret: config[:consumer]['secret'],
39
+ access_token: access_token.token,
40
+ access_token_secret: access_token.secret,
41
+ )
42
+ puts "done.\n\n"
43
+
44
+ puts <<-EOY
45
+ ---
46
+ accounts:
47
+ #{twitter.current_user.screen_name}:
48
+ token: #{access_token.token}
49
+ secret: #{access_token.secret}
50
+ EOY
51
+ end
52
+
23
53
  def help
24
54
  puts <<-EOH
25
55
  Usage:
data/lib/akane/config.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'yaml'
2
2
  require 'logger'
3
+ require 'oauth'
3
4
 
4
5
  module Akane
5
6
  class Config
@@ -18,6 +19,13 @@ module Akane
18
19
  @hash[k.to_s]
19
20
  end
20
21
 
22
+ def consumer
23
+ consumer = self[:consumer]
24
+ return nil unless consumer
25
+ OAuth::Consumer.new(consumer['token'], consumer['secret'],
26
+ site: 'https://api.twitter.com/')
27
+ end
28
+
21
29
  def logger
22
30
  Logger.new(@hash["log"] || $stdout)
23
31
  end
data/lib/akane/manager.rb CHANGED
@@ -1,4 +1,3 @@
1
- require 'eventmachine'
2
1
  require 'akane/config'
3
2
  require 'akane/recorder'
4
3
  require 'akane/receivers/stream'
@@ -53,27 +52,14 @@ module Akane
53
52
  @logger.info "Starting receivers..."
54
53
  @receivers.each(&:start)
55
54
  @logger.info "Starting recorder..."
56
- if EM.reactor_running?
57
- EM.defer { @recorder.run }
58
- else
59
- @recorder.run
60
- end
55
+ @recorder.run
61
56
  end
62
57
 
63
58
  def run
64
59
  @logger.info "Running..."
65
60
  self.prepare()
66
61
 
67
- if EM.reactor_running?
68
- start()
69
- else
70
- @logger.info "Diving into Eventmachine"
71
- EM.epoll
72
- EM.kqueue
73
- EM.run do
74
- start()
75
- end
76
- end
62
+ start()
77
63
  end
78
64
 
79
65
  private
@@ -1,61 +1,53 @@
1
1
  require 'akane/receivers/abstract_receiver'
2
- require 'tweetstream'
2
+ require 'twitter'
3
3
 
4
4
  module Akane
5
5
  module Receivers
6
6
  class Stream < AbstractReceiver
7
7
  def initialize(*)
8
8
  super
9
- @running = false
9
+ @thread = nil
10
10
  end
11
11
 
12
- def running?() @running end
12
+ def running?() !!(@thread && @thread.alive?) end
13
13
 
14
14
  def stream
15
- @stream ||= TweetStream::Client.new(
16
- auth_method: :oauth,
15
+ @stream ||= Twitter::Streaming::Client.new(
17
16
  consumer_key: @consumer[:token],
18
17
  consumer_secret: @consumer[:secret],
19
- oauth_token: @account[:token],
20
- oauth_token_secret: @account[:secret]
21
- ).tap { |stream|
22
- stream.on_anything do |hash|
23
- invoke(:event, hash) if hash["event"]
24
- end
25
-
26
- stream.on_timeline_status do |tweet|
27
- invoke(:tweet, tweet)
28
- end
29
-
30
- stream.on_delete do |tweet_id, user_id|
31
- invoke(:delete, user_id, tweet_id)
32
- end
18
+ access_token: @account[:token],
19
+ access_token_secret: @account[:secret]
20
+ )
21
+ end
33
22
 
34
- stream.on_direct_message do |message|
35
- invoke(:message, message)
36
- end
23
+ attr_reader :thread
37
24
 
38
- stream.on_inited do
39
- @logger.info "Stream: inited"
40
- end
25
+ def start
26
+ @logger.info "Stream : Starting"
41
27
 
42
- stream.on_reconnect do
43
- @logger.info "Stream: reconnected"
28
+ @thread = Thread.new do
29
+ stream.user do |obj|
30
+ case obj
31
+ when Twitter::Tweet
32
+ invoke(:tweet, obj)
33
+ when Twitter::DirectMessage
34
+ invoke(:message, obj)
35
+ when Twitter::Streaming::DeletedTweet
36
+ invoke(:delete, obj.user_id, obj.id)
37
+ when Twitter::Streaming::Event
38
+ invoke(:event,
39
+ 'event' => obj.name, 'source' => obj.source,
40
+ 'target' => obj.target, 'target_object' => obj.target_object)
41
+ end
44
42
  end
45
- }
46
- end
43
+ end
47
44
 
48
- def start
49
- @logger.info "Stream : Starting"
50
- stream.userstream
51
- @running = true
52
45
  self
53
46
  end
54
47
 
55
48
  def stop
56
- stream.stop_stream
57
- @stream = nil
58
- @running = false
49
+ @thread.tap(&:kill).join
50
+ @thread = nil
59
51
  self
60
52
  end
61
53
  end
@@ -39,11 +39,12 @@ module Akane
39
39
 
40
40
  def perform(action, account, *payload, raise_errors: false)
41
41
  if action == :record_tweet
42
- return if @recently_performed[payload.last["id"]]
43
- @recently_performed.flag!(payload.last["id"])
42
+ return if @recently_performed[payload.last[:id]]
43
+ @recently_performed.flag!(payload.last[:id])
44
44
 
45
- if payload.last["retweeted_status"]
46
- perform(:record_tweet, account, payload.last["retweeted_status"], raise_errors: raise_errors)
45
+ # WTF: Twitter::NullObject
46
+ unless payload.last[:retweeted_status].nil?
47
+ perform(:record_tweet, account, payload.last[:retweeted_status], raise_errors: raise_errors)
47
48
  end
48
49
  end
49
50
 
@@ -64,7 +65,7 @@ module Akane
64
65
  begin
65
66
  self.dequeue(raise_errors)
66
67
  rescue Exception => e
67
- raise e if e === Interrupt
68
+ raise e if Interrupt === e
68
69
  raise e if raise_errors
69
70
  @logger.error "Error while recorder dequing: #{e.inspect}"
70
71
  @logger.error e.backtrace
@@ -17,10 +17,10 @@ module Akane
17
17
  end
18
18
 
19
19
  def record_tweet(account, tweet)
20
- timeline_io.puts "[#{tweet["created_at"].xmlschema}][#{account}] #{tweet["user"]["screen_name"]}: " \
21
- "#{tweet["text"].gsub(/\r?\n/,' ')} (#{tweet["user"]["id"]},#{tweet["id"]})"
20
+ timeline_io.puts "[#{tweet[:created_at].xmlschema}][#{account}] #{tweet[:user][:screen_name]}: " \
21
+ "#{tweet[:text].gsub(/\r?\n/,' ')} (#{tweet[:user][:id]},#{tweet[:id]})"
22
22
 
23
- tweets_io_for_user(tweet["user"]["id"], tweet["user"]["screen_name"]) do |io|
23
+ tweets_io_for_user(tweet[:user][:id], tweet[:user][:screen_name]) do |io|
24
24
  io.puts tweet.attrs.to_json
25
25
  end
26
26
  end
@@ -33,16 +33,16 @@ module Akane
33
33
  end
34
34
 
35
35
  def record_event(account, event)
36
- event_io.puts event.merge("happened_on" => account).to_json
36
+ event_io.puts event.merge(:happened_on => account).to_json
37
37
  end
38
38
 
39
39
  def record_message(account, message)
40
- messages_raw_io_for_user(message["sender"]["id"], message["sender"]["screen_name"]) do |io|
40
+ messages_raw_io_for_user(message[:sender][:id], message[:sender][:screen_name]) do |io|
41
41
  io.puts message.attrs.to_json
42
42
  end
43
- messages_io_for_user(message["sender"]["id"], message["sender"]["screen_name"]) do |io|
44
- io.puts "[#{message["created_at"].xmlschema}] #{message["sender"]["screen_name"]} -> #{message["recipient"]["screen_name"]}:" \
45
- " #{message["text"]} (#{message["sender"]["id"]} -> #{message["recipient"]["id"]},#{message["id"]})"
43
+ messages_io_for_user(message[:sender][:id], message[:sender][:screen_name]) do |io|
44
+ io.puts "[#{message[:created_at].xmlschema}] #{message[:sender][:screen_name]} -> #{message[:recipient][:screen_name]}:" \
45
+ " #{message[:text]} (#{message[:sender][:id]} -> #{message[:recipient][:id]},#{message[:id]})"
46
46
  end
47
47
  end
48
48
 
data/lib/akane/util.rb ADDED
@@ -0,0 +1,18 @@
1
+ module Akane
2
+ module Util
3
+ class << self
4
+ def symbolish_hash(hash)
5
+ Hash[hash.map { |k, v|
6
+ [
7
+ k.is_a?(Symbol) ? k : k.to_s.to_sym,
8
+ case v
9
+ when Hash; symbolish_hash(v)
10
+ when Array; v.map{ |i| i.kind_of?(Hash) ? symbolish_hash(i) : i }
11
+ else; v
12
+ end
13
+ ]
14
+ }]
15
+ end
16
+ end
17
+ end
18
+ end
data/lib/akane/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Akane
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
data/spec/manager_spec.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'eventmachine'
3
2
  require 'akane/manager'
4
3
  require 'akane/receivers/stream'
5
4
  require 'akane/storages/mock'
@@ -29,10 +28,6 @@ describe Akane::Manager do
29
28
 
30
29
  subject { Akane::Manager.new(config) }
31
30
 
32
- before do
33
- EM.stub(:run) { |&block| block.call }
34
- end
35
-
36
31
  # receivers -> manager -> recorder -> storage
37
32
 
38
33
  describe "#prepare" do
@@ -7,13 +7,13 @@ describe Akane::Receivers::Stream do
7
7
  subject { described_class.new(consumer: {token: 'consumer-token', secret: 'consumer-secret'}, account: {token: '42-access-token', secret: 'access-secret'}, config: config, logger: Logger.new(nil)) }
8
8
 
9
9
  after(:each) do
10
- TweetStream::MockClient.clients.clear
10
+ Twitter::Streaming::MockClient.clients.clear
11
11
  end
12
12
 
13
13
  describe "#start" do
14
14
  it "starts listening" do
15
- expect { subject.start } \
16
- .to change { TweetStream::MockClient.clients.size } \
15
+ expect { subject.start; 100.times { break if subject.thread.status == 'sleep'; sleep 0.1 } } \
16
+ .to change { Twitter::Streaming::MockClient.clients.size } \
17
17
  .by(1)
18
18
  end
19
19
 
@@ -27,11 +27,12 @@ describe Akane::Receivers::Stream do
27
27
  describe "#stop" do
28
28
  before do
29
29
  subject.start
30
+ 100.times { break if subject.thread.status == 'sleep'; sleep 0.1 }
30
31
  end
31
32
 
32
33
  it "stops listening" do
33
34
  expect { subject.stop } \
34
- .to change { TweetStream::MockClient.clients.size } \
35
+ .to change { Twitter::Streaming::MockClient.clients.size } \
35
36
  .by(-1)
36
37
  end
37
38
 
@@ -45,36 +46,51 @@ describe Akane::Receivers::Stream do
45
46
  describe "when received tweet" do
46
47
  before do
47
48
  subject.start
49
+ 100.times { break if subject.thread.status == 'sleep'; sleep 0.1 }
48
50
  end
49
51
 
50
52
  it "calls on_tweet hook" do
51
53
  called = nil
52
- subject.on_tweet do |tweet|
53
- called = tweet
54
+ subject.on_tweet do |t|
55
+ called = t
54
56
  end
55
- TweetStream::MockClient.invoke('timeline_status', foo: :bar)
56
- expect(called).to eq(foo: :bar)
57
+
58
+ tweet = Twitter::Tweet.new(id: 1)
59
+ Twitter::Streaming::MockClient.invoke(tweet)
60
+
61
+ Twitter::Streaming::MockClient.invoke(:disconnect)
62
+ subject.thread.join
63
+
64
+ expect(called).to eq(tweet)
57
65
  end
58
66
  end
59
67
 
60
68
  describe "when received message" do
61
69
  before do
62
70
  subject.start
71
+ 100.times { break if subject.thread.status == 'sleep'; sleep 0.1 }
63
72
  end
64
73
 
65
74
  it "calls on_message hook" do
66
75
  called = nil
67
- subject.on_message do |message|
68
- called = message
76
+ subject.on_message do |m|
77
+ called = m
69
78
  end
70
- TweetStream::MockClient.invoke('direct_message', foo: :bar)
71
- expect(called).to eq(foo: :bar)
79
+
80
+ message = Twitter::DirectMessage.new(id: 1)
81
+ Twitter::Streaming::MockClient.invoke(message)
82
+
83
+ Twitter::Streaming::MockClient.invoke(:disconnect)
84
+ subject.thread.join
85
+
86
+ expect(called).to eq(message)
72
87
  end
73
88
  end
74
89
 
75
90
  describe "when received deletion" do
76
91
  before do
77
92
  subject.start
93
+ 100.times { break if subject.thread.status == 'sleep'; sleep 0.1 }
78
94
  end
79
95
 
80
96
  it "calls on_delete hook" do
@@ -82,7 +98,13 @@ describe Akane::Receivers::Stream do
82
98
  subject.on_delete do |u,t|
83
99
  called = [u,t]
84
100
  end
85
- TweetStream::MockClient.invoke('delete', 424242, 42)
101
+
102
+ deletion = Twitter::Streaming::DeletedTweet.new(user_id: 42, id: 424242)
103
+ Twitter::Streaming::MockClient.invoke(deletion)
104
+
105
+ Twitter::Streaming::MockClient.invoke(:disconnect)
106
+ subject.thread.join
107
+
86
108
  expect(called).to eq([42,424242])
87
109
  end
88
110
  end
@@ -90,6 +112,7 @@ describe Akane::Receivers::Stream do
90
112
  describe "when received event" do
91
113
  before do
92
114
  subject.start
115
+ 100.times { break if subject.thread.status == 'sleep'; sleep 0.1 }
93
116
  end
94
117
 
95
118
  it "calls on_event hook" do
@@ -97,9 +120,14 @@ describe Akane::Receivers::Stream do
97
120
  subject.on_event do |h|
98
121
  called = h
99
122
  end
100
- TweetStream::MockClient.invoke('anything', "event" => "favorite")
101
- TweetStream::MockClient.invoke('anything', "something" => "else")
102
- expect(called).to eq("event" => "favorite")
123
+ event = Twitter::Streaming::Event.new(event: 'favorite', source: {id: 1}, target: {id: 2}, target_object: {id: 3})
124
+ Twitter::Streaming::MockClient.invoke(event)
125
+
126
+ Twitter::Streaming::MockClient.invoke(:disconnect)
127
+ subject.thread.join
128
+
129
+ expect(called).to eq('event' => event.name, 'source' => event.source,
130
+ 'target' => event.target, 'target_object' => event.target_object)
103
131
  end
104
132
  end
105
133
  end
@@ -11,26 +11,26 @@ describe Akane::Recorder do
11
11
 
12
12
  describe "recording tweets" do
13
13
  it "records tweet" do
14
- storages[0].should_receive(:record_tweet).with('a', {"id" => 42})
15
- subject.record_tweet('a', "id" => 42)
14
+ storages[0].should_receive(:record_tweet).with('a', {id: 42})
15
+ subject.record_tweet('a', id: 42)
16
16
  subject.dequeue(true)
17
17
  end
18
18
 
19
19
  it "doesn't record tweets which already recorded recently" do
20
- storages[0].should_receive(:record_tweet).with('a', {"id" => 40})
21
- storages[0].should_receive(:record_tweet).with('a', {"id" => 42})
20
+ storages[0].should_receive(:record_tweet).with('a', {id: 40})
21
+ storages[0].should_receive(:record_tweet).with('a', {id: 42})
22
22
 
23
- subject.record_tweet('a', "id" => 40)
24
- subject.record_tweet('a', "id" => 42)
23
+ subject.record_tweet('a', id: 40)
24
+ subject.record_tweet('a', id: 42)
25
25
  subject.dequeue(true)
26
26
  subject.dequeue(true)
27
- subject.record_tweet('a', "id" => 42)
27
+ subject.record_tweet('a', id: 42)
28
28
  subject.dequeue(true)
29
29
  end
30
30
 
31
31
  it "records retweeted tweet" do
32
- tweet = {"id" => 42, "text" => "foo", "user" => {"id" => 1, "screen_name" => "a"}}
33
- retweet = {"id" => 43, "text" => "RT @a: foo", "user" => {"id" => 2, "screen_name" => "b"}, "retweeted_status" => tweet}
32
+ tweet = {id: 42, text: "foo", user: {id: 1, screen_name: "a"}}
33
+ retweet = {id: 43, text: "RT @a: foo", user: {id: 2, screen_name: "b"}, retweeted_status: tweet}
34
34
  storages[0].should_receive(:record_tweet).with('a', retweet)
35
35
  storages[0].should_receive(:record_tweet).with('a', tweet)
36
36
  subject.record_tweet('a', retweet)
@@ -49,18 +49,18 @@ describe Akane::Recorder do
49
49
 
50
50
  describe "recording messages" do
51
51
  it "records message" do
52
- subject.record_message('foo', {"id" => 42})
52
+ subject.record_message('foo', {id: 42})
53
53
 
54
- storages[0].should_receive(:record_message).with('foo', "id" => 42)
54
+ storages[0].should_receive(:record_message).with('foo', id: 42)
55
55
  subject.dequeue(true)
56
56
  end
57
57
  end
58
58
 
59
59
  describe "recording event" do
60
60
  it "records event" do
61
- subject.record_event('foo', {"event" => "favorite"})
61
+ subject.record_event('foo', {event: "favorite"})
62
62
 
63
- storages[0].should_receive(:record_event).with('foo', "event" => "favorite")
63
+ storages[0].should_receive(:record_event).with('foo', event: "favorite")
64
64
  subject.dequeue(true)
65
65
  end
66
66
  end
@@ -72,10 +72,10 @@ describe Akane::Recorder do
72
72
  end
73
73
 
74
74
  it "continues dequeuing the queue" do
75
- storages[0].should_receive(:record_tweet).with('a', {"id" => 42})
76
- storages[0].should_receive(:record_tweet).with('b', {"id" => 43})
77
- subject.record_tweet('a', "id" => 42)
78
- subject.record_tweet('b', "id" => 43)
75
+ storages[0].should_receive(:record_tweet).with('a', {:id => 42})
76
+ storages[0].should_receive(:record_tweet).with('b', {:id => 43})
77
+ subject.record_tweet('a', :id => 42)
78
+ subject.record_tweet('b', :id => 43)
79
79
  10.times { break if subject.queue_length.zero?; sleep 0.1 }
80
80
  end
81
81
 
data/spec/spec_helper.rb CHANGED
@@ -13,4 +13,4 @@ RSpec.configure do |config|
13
13
  config.order = 'random'
14
14
  end
15
15
 
16
- require_relative './support/mock_tweetstream'
16
+ require_relative './support/mock_twitter_streaming'
@@ -0,0 +1,98 @@
1
+ require 'twitter'
2
+ require 'thread'
3
+
4
+ class Twitter::Streaming::MockClient
5
+ Original = Twitter::Streaming::Client
6
+
7
+ class << self
8
+ def clients
9
+ @clients ||= []
10
+ end
11
+
12
+ def clients_mutex
13
+ @clients_mutex ||= Mutex.new
14
+ end
15
+
16
+ def add_client(client)
17
+ clients_mutex.synchronize {
18
+ clients << client
19
+ }
20
+ end
21
+
22
+ def remove_client(client)
23
+ clients_mutex.synchronize {
24
+ clients.delete client
25
+ }
26
+ end
27
+
28
+ def invoke(*args)
29
+ clients.each do |client|
30
+ client.invoke(*args)
31
+ end
32
+
33
+ self
34
+ end
35
+
36
+ def enable!
37
+ klass = self
38
+ Twitter::Streaming.instance_eval {
39
+ remove_const :Client
40
+ const_set :Client, klass
41
+ }
42
+ end
43
+
44
+ def disable!
45
+ klass = Original
46
+ Twitter::Streaming.instance_eval {
47
+ remove_const :Client
48
+ const_set :Client, klass
49
+ }
50
+ end
51
+ end
52
+
53
+ def initialize(options={})
54
+ @options = options
55
+ @queues = []
56
+ @mutex = Mutex.new
57
+ end
58
+
59
+ attr_accessor :options, :hooks
60
+
61
+ def invoke(*args)
62
+ @queues.each do |queue|
63
+ queue << args
64
+ end
65
+ end
66
+
67
+ def user(options = {}, &block)
68
+ connect(&block)
69
+ end
70
+
71
+ private
72
+
73
+ def connect
74
+ queue = Queue.new
75
+ was_empty = nil
76
+ @mutex.synchronize {
77
+ was_empty = @queues.empty?
78
+ @queues << queue
79
+
80
+ if was_empty
81
+ self.class.add_client self
82
+ end
83
+ }
84
+ while _ = queue.pop
85
+ break if _ == [:disconnect]
86
+ yield *_
87
+ end
88
+ ensure
89
+ @mutex.synchronize {
90
+ @queues.delete queue
91
+ if @queues.empty?
92
+ self.class.remove_client self
93
+ end
94
+ }
95
+ end
96
+ end
97
+
98
+ Twitter::Streaming::MockClient.enable!
data/spec/util_spec.rb ADDED
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+ require 'akane/util'
3
+
4
+ describe Akane::Util do
5
+ describe ".symbolish_hash" do
6
+ let(:target) { {'a' => 1, 'b' => 2} }
7
+ subject { described_class.symbolish_hash(target) }
8
+
9
+ it { should eq(a: 1, b: 2) }
10
+
11
+ context "with Hash" do
12
+ let(:target) { {'a' => {'b' => 2}} }
13
+ it { should eq(a: {b: 2}) }
14
+
15
+ context "with nested Hash" do
16
+ let(:target) { {'a' => {'b' => {'c' => 4}}} }
17
+ it { should eq(a: {b: {c: 4}}) }
18
+ end
19
+
20
+ context "with nested Array" do
21
+ let(:target) { {'a' => {'b' => [{'c' => 4}]}} }
22
+ it { should eq(a: {b: [{c: 4}]}) }
23
+ end
24
+
25
+ context "with nested Array" do
26
+ let(:target) { {'a' => {'b' => [{'c' => {'d' => 5}}]}} }
27
+ it { should eq(a: {b: [{c: {d: 5}}]}) }
28
+ end
29
+ end
30
+
31
+ context "with Hash in Array" do
32
+ let(:target) { {'a' => [1,2,{'b' => 3}]} }
33
+ it { should eq(a: [1,2,{b: 3}]) }
34
+ end
35
+ end
36
+ end
metadata CHANGED
@@ -1,43 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: akane
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.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-01-14 00:00:00.000000000 Z
11
+ date: 2014-01-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: tweetstream
14
+ name: elasticsearch
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 2.6.0
19
+ version: 0.4.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 2.6.0
26
+ version: 0.4.1
27
27
  - !ruby/object:Gem::Dependency
28
- name: elasticsearch
28
+ name: twitter
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.4.1
33
+ version: 5.5.1
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.4.1
40
+ version: 5.5.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: oauth
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 0.4.7
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 0.4.7
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -122,6 +136,7 @@ files:
122
136
  - lib/akane/storages/file.rb
123
137
  - lib/akane/storages/mock.rb
124
138
  - lib/akane/storages/stdout.rb
139
+ - lib/akane/util.rb
125
140
  - lib/akane/version.rb
126
141
  - spec/config_spec.rb
127
142
  - spec/manager_spec.rb
@@ -132,6 +147,8 @@ files:
132
147
  - spec/storages/abstract_storage_spec.rb
133
148
  - spec/storages/mock_spec.rb
134
149
  - spec/support/mock_tweetstream.rb
150
+ - spec/support/mock_twitter_streaming.rb
151
+ - spec/util_spec.rb
135
152
  homepage: https://github.com/sorah/akane
136
153
  licenses:
137
154
  - MIT
@@ -166,4 +183,6 @@ test_files:
166
183
  - spec/storages/abstract_storage_spec.rb
167
184
  - spec/storages/mock_spec.rb
168
185
  - spec/support/mock_tweetstream.rb
186
+ - spec/support/mock_twitter_streaming.rb
187
+ - spec/util_spec.rb
169
188
  has_rdoc: