streamit 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +5 -1
- data/README.rdoc +32 -0
- data/TODO +2 -33
- data/app/controllers/streamit/streams_controller.rb +8 -3
- data/app/views/streamit/streams/fetch.html.erb +1 -1
- data/lib/generators/streamit_generator.rb +4 -0
- data/lib/generators/templates/_stream.html.erb +1 -2
- data/lib/generators/templates/streamit.rb +3 -0
- data/lib/streamit.rb +29 -3
- data/lib/streamit/dsl.rb +30 -14
- data/lib/streamit/orm/active_record.rb +0 -2
- data/lib/streamit/orm/mongo_mapper.rb +23 -0
- data/test/dummy/app/models/stream.rb +3 -2
- data/test/dummy/config/initializers/streamit.rb +3 -0
- data/test/dummy/config/locales/en.yml +0 -3
- data/test/integration/navigation_test.rb +17 -4
- data/test/streamit_test.rb +12 -1
- data/test/test_helper.rb +5 -1
- metadata +6 -2
data/Gemfile
CHANGED
@@ -7,4 +7,8 @@ gem "sqlite3-ruby", :require => "sqlite3"
|
|
7
7
|
gem "mocha", ">= 0.9.10"
|
8
8
|
gem "shoulda-context", "1.0.0.beta1"
|
9
9
|
gem "launchy", ">= 0.3.7"
|
10
|
-
gem "timecop", ">= 0.3.5"
|
10
|
+
gem "timecop", ">= 0.3.5"
|
11
|
+
|
12
|
+
gem "mongo_mapper", "~> 0.9.1"
|
13
|
+
gem "mongo", "~> 1.3.1"
|
14
|
+
gem 'bson_ext', "~> 1.3.1"
|
data/README.rdoc
CHANGED
@@ -1,2 +1,34 @@
|
|
1
1
|
= Streamit (Under development)
|
2
2
|
|
3
|
+
Provides feed stream like feature to rails apps
|
4
|
+
|
5
|
+
class Stream
|
6
|
+
include MongoMapper::Document
|
7
|
+
include Streamit::ORM::MongoMapper
|
8
|
+
end
|
9
|
+
|
10
|
+
# "he9lin started watching auction ipad a minute ago"
|
11
|
+
#
|
12
|
+
# en:
|
13
|
+
# streamit:
|
14
|
+
# watching:
|
15
|
+
# create: "started watching"
|
16
|
+
#
|
17
|
+
class Watching < ActiveRecord::Base
|
18
|
+
belongs_to :watcher, :class_name => "User", :foreign_key => "user_id"
|
19
|
+
belongs_to :watched_item, :class_name => "Item", :foreign_key => "item_id"
|
20
|
+
|
21
|
+
stream :create, :actor => :watcher,
|
22
|
+
:receiver => :watched_item
|
23
|
+
end
|
24
|
+
|
25
|
+
# "he9lin edited profile image just now"
|
26
|
+
#
|
27
|
+
# en:
|
28
|
+
# users:
|
29
|
+
# update:
|
30
|
+
# image_url: "edited profile image"
|
31
|
+
#
|
32
|
+
class User < ActiveRecord::Base
|
33
|
+
stream :update, :attributes => :image_url
|
34
|
+
end
|
data/TODO
CHANGED
@@ -1,35 +1,4 @@
|
|
1
1
|
TODO:
|
2
|
-
- use background job like tool to process creating of streams
|
3
|
-
- customizable views
|
4
|
-
- cleanup old streams
|
5
|
-
- add more detailed documentation
|
6
2
|
|
7
|
-
|
8
|
-
|
9
|
-
belongs_to :subject, :polymorphic => true
|
10
|
-
belongs_to :receiver, :polymorphic => true
|
11
|
-
end
|
12
|
-
|
13
|
-
# "he9lin started watching auction ipad 001 a minute ago"
|
14
|
-
#
|
15
|
-
# en:
|
16
|
-
# streamit:
|
17
|
-
# watching:
|
18
|
-
# create: "started watching"
|
19
|
-
|
20
|
-
class Watching < ActiveRecord::Base
|
21
|
-
belongs_to :watcher, :class_name => "User", :foreign_key => "user_id"
|
22
|
-
belongs_to :watched_item, :class_name => "Item", :foreign_key => "item_id"
|
23
|
-
|
24
|
-
stream :create, :actor => :watcher,
|
25
|
-
:receiver => :watched_item
|
26
|
-
end
|
27
|
-
|
28
|
-
# "he9lin just edited profile image just now"
|
29
|
-
#
|
30
|
-
# stream:
|
31
|
-
# stream_type: 'user.update.image_url'
|
32
|
-
#
|
33
|
-
class User < ActiveRecord::Base
|
34
|
-
stream :update, :attributes => :image_url
|
35
|
-
end
|
3
|
+
Support json format
|
4
|
+
Refactor
|
@@ -15,9 +15,14 @@ class Streamit::StreamsController < ApplicationController
|
|
15
15
|
private
|
16
16
|
|
17
17
|
def process_params
|
18
|
-
@streams = [:ago, :
|
19
|
-
|
20
|
-
|
18
|
+
@streams = [:ago, :limit].inject(store) do |memo, sym|
|
19
|
+
case sym
|
20
|
+
when :limit
|
21
|
+
params[sym] ? memo.send(sym, params[sym].to_i) : memo
|
22
|
+
else
|
23
|
+
params[sym] ? memo.send(sym, params[sym]) : memo
|
24
|
+
end
|
21
25
|
end
|
22
26
|
end
|
27
|
+
|
23
28
|
end
|
@@ -1 +1 @@
|
|
1
|
-
<%= render @streams %>
|
1
|
+
<%= render @streams.all %>
|
data/lib/streamit.rb
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
require 'active_support/core_ext/hash'
|
2
|
+
require "mongo_mapper"
|
3
|
+
|
4
|
+
# We are required to choose a database name
|
5
|
+
MongoMapper.database = "streamit-#{Rails.env}"
|
2
6
|
|
3
7
|
module Streamit
|
4
8
|
autoload :DSL, 'streamit/dsl'
|
5
9
|
autoload :Store, 'streamit/store'
|
6
10
|
|
7
|
-
|
8
|
-
|
11
|
+
def self.setup
|
12
|
+
yield self
|
9
13
|
end
|
10
14
|
|
11
15
|
# Set which store to use.
|
@@ -20,8 +24,30 @@ module Streamit
|
|
20
24
|
def self.store; end
|
21
25
|
|
22
26
|
def self.save_stream!(args)
|
23
|
-
|
27
|
+
# insert to queue
|
28
|
+
self.queue << args
|
29
|
+
end
|
30
|
+
|
31
|
+
# Queue related methods
|
32
|
+
def self.finish!
|
33
|
+
queue << nil
|
34
|
+
thread.join
|
35
|
+
@thread = nil
|
36
|
+
thread
|
24
37
|
end
|
38
|
+
|
39
|
+
def self.queue
|
40
|
+
@queue ||= Queue.new
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.thread
|
44
|
+
@thread ||= Thread.new do
|
45
|
+
while args = queue.pop
|
46
|
+
store.save_stream!(args)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
25
51
|
end
|
26
52
|
|
27
53
|
require 'streamit/engine'
|
data/lib/streamit/dsl.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
module Streamit
|
2
2
|
module DSL
|
3
3
|
extend ActiveSupport::Concern
|
4
|
-
|
4
|
+
|
5
|
+
# A class method for ActiveRecord models
|
6
|
+
#
|
7
|
+
# Sample usage:
|
8
|
+
#
|
5
9
|
# stream :create, :actor => :watcher,
|
6
10
|
# :receiver => :watched_item
|
7
11
|
#
|
@@ -9,7 +13,7 @@ module Streamit
|
|
9
13
|
#
|
10
14
|
module ClassMethods
|
11
15
|
def stream(action, options={})
|
12
|
-
options.assert_valid_keys(:
|
16
|
+
options.assert_valid_keys(:actor, :subject, :receiver, :attributes)
|
13
17
|
raise ArgumentError, ":create or :update required as first parameter" \
|
14
18
|
unless [:create, :update].any? {|sym| sym == action }
|
15
19
|
|
@@ -27,26 +31,38 @@ module Streamit
|
|
27
31
|
|
28
32
|
stream_type = attr_name.nil? ? "streamit.#{table_name}.#{action}" :
|
29
33
|
"streamit.#{table_name}.#{action}.#{attr_name}"
|
30
|
-
|
34
|
+
|
31
35
|
method_name = :"_#{stream_type.gsub('.', '_')}"
|
36
|
+
|
32
37
|
define_method(method_name) do
|
33
38
|
stream_options = [:actor, :receiver, :subject].inject({}) do |memo, sym|
|
34
39
|
memo[sym] = options[sym] ? send(options[sym]) : (sym == :actor ? self : nil)
|
35
40
|
memo
|
36
41
|
end.merge(:stream_type => stream_type, :started_at => Time.now)
|
37
42
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
43
|
+
if (action != :update || instance_variable_get("@attr_changed"))
|
44
|
+
Streamit.save_stream!(stream_options)
|
45
|
+
end
|
46
|
+
|
47
|
+
instance_variable_set("@attr_changed", false)
|
48
|
+
end
|
49
|
+
|
50
|
+
if action == :update
|
51
|
+
before_update_method_name = "_before#{method_name}"
|
52
|
+
define_method(before_update_method_name) do
|
53
|
+
attr_changed = if action == :update
|
54
|
+
case attributes
|
55
|
+
when nil
|
56
|
+
changed?
|
57
|
+
when Array
|
58
|
+
attributes.any? { |attr| send(:"#{attr}_changed?") }
|
59
|
+
when Symbol
|
60
|
+
send(:"#{attributes}_changed?")
|
61
|
+
end
|
46
62
|
end
|
63
|
+
instance_variable_set("@attr_changed", attr_changed)
|
47
64
|
end
|
48
|
-
|
49
|
-
Streamit.save_stream!(stream_options) if (action != :update || attr_changed)
|
65
|
+
send(:"before_update", before_update_method_name)
|
50
66
|
end
|
51
67
|
|
52
68
|
send(:"after_#{action}", method_name)
|
@@ -54,4 +70,4 @@ module Streamit
|
|
54
70
|
end
|
55
71
|
|
56
72
|
end # DSL
|
57
|
-
end # Streamit
|
73
|
+
end # Streamit
|
@@ -11,13 +11,11 @@ module Streamit
|
|
11
11
|
|
12
12
|
default_scope order("started_at DESC")
|
13
13
|
scope :ago, lambda { |num| where ["started_at > ?", Time.now - num.to_i.seconds] }
|
14
|
-
scope :after, lambda { |id| where("id > #{id}") }
|
15
14
|
end
|
16
15
|
|
17
16
|
def save_stream!
|
18
17
|
save!
|
19
18
|
end
|
20
19
|
end
|
21
|
-
|
22
20
|
end
|
23
21
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Streamit
|
2
|
+
module ORM
|
3
|
+
module MongoMapper
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
include Streamit::Store
|
6
|
+
|
7
|
+
included do
|
8
|
+
key :stream_type, String
|
9
|
+
key :started_at, Time
|
10
|
+
|
11
|
+
belongs_to :actor, :polymorphic => true
|
12
|
+
belongs_to :subject, :polymorphic => true
|
13
|
+
belongs_to :receiver, :polymorphic => true
|
14
|
+
|
15
|
+
scope :ago, lambda { |num| where(:started_at.gt => Time.now - num.to_i.seconds) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def save_stream!
|
19
|
+
save!
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,17 +1,25 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class NavigationTest < ActiveSupport::IntegrationCase
|
4
|
+
|
5
|
+
def wait_and_finish
|
6
|
+
Streamit.finish!
|
7
|
+
end
|
4
8
|
|
5
9
|
def register_new_user
|
6
10
|
visit "/users/new"
|
7
11
|
fill_in "Name", :with => "davis"
|
8
12
|
click_button "Create User"
|
13
|
+
wait_and_finish
|
9
14
|
end
|
10
15
|
|
11
|
-
should "fetch
|
16
|
+
should "fetch limited number of streams" do
|
17
|
+
register_new_user
|
18
|
+
register_new_user
|
12
19
|
register_new_user
|
13
20
|
register_new_user
|
14
|
-
|
21
|
+
wait_and_finish
|
22
|
+
visit "/streamit/fetch?limit=2"
|
15
23
|
assert page.has_selector?("li.stream", :count => 2), "Expected 2 streams, Got:\n#{page.body.inspect}"
|
16
24
|
end
|
17
25
|
|
@@ -21,15 +29,20 @@ class NavigationTest < ActiveSupport::IntegrationCase
|
|
21
29
|
end
|
22
30
|
register_new_user
|
23
31
|
register_new_user
|
32
|
+
wait_and_finish
|
24
33
|
visit "/streamit/fetch?ago=30"
|
25
34
|
assert page.has_selector?("li.stream", :count => 2), "Expected 2 streams, Got:\n#{page.body.inspect}"
|
26
35
|
end
|
27
36
|
|
28
|
-
should "fetch streams
|
37
|
+
should "fetch limited number of streams in last ? seconds" do
|
38
|
+
Timecop.freeze(Time.now - 30.seconds) do
|
39
|
+
register_new_user
|
40
|
+
end
|
29
41
|
register_new_user
|
30
42
|
register_new_user
|
31
43
|
register_new_user
|
32
|
-
|
44
|
+
wait_and_finish
|
45
|
+
visit "/streamit/fetch?ago=30&limit=2"
|
33
46
|
assert page.has_selector?("li.stream", :count => 2), "Expected 2 streams, Got:\n#{page.body.inspect}"
|
34
47
|
end
|
35
48
|
|
data/test/streamit_test.rb
CHANGED
@@ -5,6 +5,10 @@ class StreamitTest < ActiveSupport::TestCase
|
|
5
5
|
Streamit.store
|
6
6
|
end
|
7
7
|
|
8
|
+
def wait_and_finish
|
9
|
+
Streamit.finish!
|
10
|
+
end
|
11
|
+
|
8
12
|
context "when user watches an item" do
|
9
13
|
setup do
|
10
14
|
TestWatching.class_eval do
|
@@ -15,6 +19,7 @@ class StreamitTest < ActiveSupport::TestCase
|
|
15
19
|
|
16
20
|
should "create a stream if watching is created successfully" do
|
17
21
|
@watch.save
|
22
|
+
wait_and_finish
|
18
23
|
stream = stream_store.last
|
19
24
|
assert_not_nil stream
|
20
25
|
assert_equal "streamit.testwatchings.create", stream.stream_type
|
@@ -27,7 +32,7 @@ class StreamitTest < ActiveSupport::TestCase
|
|
27
32
|
TestWatching.class_eval do
|
28
33
|
before_create { return false }
|
29
34
|
end
|
30
|
-
assert_no_difference("stream_store.count") { @watch.save }
|
35
|
+
assert_no_difference("stream_store.count") { @watch.save; wait_and_finish }
|
31
36
|
end
|
32
37
|
end
|
33
38
|
|
@@ -44,6 +49,7 @@ class StreamitTest < ActiveSupport::TestCase
|
|
44
49
|
stream :create
|
45
50
|
end
|
46
51
|
@user.save
|
52
|
+
wait_and_finish
|
47
53
|
stream = stream_store.last
|
48
54
|
assert_not_nil stream
|
49
55
|
assert_equal "streamit.testusers.create", stream.stream_type
|
@@ -55,6 +61,7 @@ class StreamitTest < ActiveSupport::TestCase
|
|
55
61
|
context "when user updates her attributes" do
|
56
62
|
setup do
|
57
63
|
@user.save
|
64
|
+
wait_and_finish
|
58
65
|
end
|
59
66
|
|
60
67
|
should "create a stream the attribute specified has changed" do
|
@@ -63,6 +70,7 @@ class StreamitTest < ActiveSupport::TestCase
|
|
63
70
|
end
|
64
71
|
@user.image_url = "image"
|
65
72
|
@user.save
|
73
|
+
wait_and_finish
|
66
74
|
stream = stream_store.last
|
67
75
|
assert_not_nil stream
|
68
76
|
assert_equal "streamit.testusers.update.image_url", stream.stream_type
|
@@ -77,6 +85,7 @@ class StreamitTest < ActiveSupport::TestCase
|
|
77
85
|
end
|
78
86
|
@user.name = "davis"
|
79
87
|
@user.save
|
88
|
+
wait_and_finish
|
80
89
|
stream = stream_store.last
|
81
90
|
assert_not_nil stream
|
82
91
|
assert_equal "streamit.testusers.update.default", stream.stream_type
|
@@ -91,6 +100,7 @@ class StreamitTest < ActiveSupport::TestCase
|
|
91
100
|
end
|
92
101
|
@user.name = "davis"
|
93
102
|
@user.save
|
103
|
+
wait_and_finish
|
94
104
|
stream = stream_store.last
|
95
105
|
assert_not_nil stream
|
96
106
|
assert_equal "streamit.testusers.update.default", stream.stream_type
|
@@ -109,6 +119,7 @@ class StreamitTest < ActiveSupport::TestCase
|
|
109
119
|
end
|
110
120
|
@user.image_url = "image"
|
111
121
|
@user.save
|
122
|
+
wait_and_finish
|
112
123
|
assert_equal 0, stream_store.count
|
113
124
|
end
|
114
125
|
end
|
data/test/test_helper.rb
CHANGED
@@ -19,4 +19,8 @@ Capybara.default_selector = :css
|
|
19
19
|
ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__)
|
20
20
|
|
21
21
|
# Load support files
|
22
|
-
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
22
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
23
|
+
|
24
|
+
class ActiveSupport::TestCase
|
25
|
+
setup { Streamit.store.delete_all }
|
26
|
+
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 6
|
9
|
+
version: 0.0.6
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Lin He
|
@@ -38,11 +38,13 @@ files:
|
|
38
38
|
- lib/streamit.rb
|
39
39
|
- lib/generators/streamit_generator.rb
|
40
40
|
- lib/generators/templates/_stream.html.erb
|
41
|
+
- lib/generators/templates/streamit.rb
|
41
42
|
- lib/streamit/dsl.rb
|
42
43
|
- lib/streamit/engine.rb
|
43
44
|
- lib/streamit/store.rb
|
44
45
|
- lib/streamit/locales/en.yml
|
45
46
|
- lib/streamit/orm/active_record.rb
|
47
|
+
- lib/streamit/orm/mongo_mapper.rb
|
46
48
|
- test/dummy/app/controllers/application_controller.rb
|
47
49
|
- test/dummy/app/controllers/users_controller.rb
|
48
50
|
- test/dummy/app/models/stream.rb
|
@@ -64,6 +66,7 @@ files:
|
|
64
66
|
- test/dummy/config/initializers/backtrace_silencers.rb
|
65
67
|
- test/dummy/config/initializers/secret_token.rb
|
66
68
|
- test/dummy/config/initializers/session_store.rb
|
69
|
+
- test/dummy/config/initializers/streamit.rb
|
67
70
|
- test/dummy/config/locales/en.yml
|
68
71
|
- test/dummy/db/migrate/20110204210955_create_users.rb
|
69
72
|
- test/dummy/db/migrate/20110204210910_create_items.rb
|
@@ -137,6 +140,7 @@ test_files:
|
|
137
140
|
- test/dummy/config/initializers/backtrace_silencers.rb
|
138
141
|
- test/dummy/config/initializers/secret_token.rb
|
139
142
|
- test/dummy/config/initializers/session_store.rb
|
143
|
+
- test/dummy/config/initializers/streamit.rb
|
140
144
|
- test/dummy/config/locales/en.yml
|
141
145
|
- test/dummy/db/migrate/20110204210955_create_users.rb
|
142
146
|
- test/dummy/db/migrate/20110204210910_create_items.rb
|