activity_stream 0.0.2 → 0.0.3
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 +2 -1
- data/Gemfile.lock +9 -1
- data/app/models/activity_stream/activity.rb +77 -0
- data/generators/activity_stream/activity_stream_generator.rb +2 -2
- data/generators/activity_stream/templates/{example_activity.rb → initializer.rb} +0 -0
- data/lib/activity_stream/actor.rb +8 -6
- data/lib/activity_stream/definition.rb +23 -39
- data/lib/activity_stream/definition_proxy.rb +49 -0
- data/lib/activity_stream/metadata.rb +45 -4
- data/lib/activity_stream/stream.rb +3 -1
- data/lib/activity_stream/version.rb +1 -1
- data/spec/lib/metadata_spec.rb +43 -0
- metadata +9 -6
- data/app/models/activity.rb +0 -46
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
activity_stream (0.0.
|
4
|
+
activity_stream (0.0.3)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: http://rubygems.org/
|
@@ -28,10 +28,12 @@ GEM
|
|
28
28
|
celerity (0.8.2)
|
29
29
|
childprocess (0.1.3)
|
30
30
|
ffi (~> 0.6.3)
|
31
|
+
columnize (0.3.1)
|
31
32
|
culerity (0.2.12)
|
32
33
|
ffi (0.6.3)
|
33
34
|
rake (>= 0.8.7)
|
34
35
|
json_pure (1.4.6)
|
36
|
+
linecache (0.43)
|
35
37
|
mime-types (1.16)
|
36
38
|
nokogiri (1.4.3.1)
|
37
39
|
rack (1.1.0)
|
@@ -49,6 +51,11 @@ GEM
|
|
49
51
|
rspec-rails (1.3.3)
|
50
52
|
rack (>= 1.0.0)
|
51
53
|
rspec (= 1.3.1)
|
54
|
+
ruby-debug (0.10.3)
|
55
|
+
columnize (>= 0.1)
|
56
|
+
ruby-debug-base (~> 0.10.3.0)
|
57
|
+
ruby-debug-base (0.10.3)
|
58
|
+
linecache (>= 0.3)
|
52
59
|
rubyzip (0.9.4)
|
53
60
|
selenium-webdriver (0.0.29)
|
54
61
|
childprocess (>= 0.0.7)
|
@@ -67,4 +74,5 @@ DEPENDENCIES
|
|
67
74
|
capybara
|
68
75
|
rails (~> 2.3.10)
|
69
76
|
rspec-rails (~> 1.3.0)
|
77
|
+
ruby-debug
|
70
78
|
sqlite3-ruby
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module ActivityStream
|
2
|
+
|
3
|
+
class Activity < ActiveRecord::Base
|
4
|
+
|
5
|
+
belongs_to :actor, :polymorphic => true
|
6
|
+
|
7
|
+
before_save :ensure_occurred_at_set
|
8
|
+
|
9
|
+
# @param name [Symbol] (see ActivityStream::Definition#new)
|
10
|
+
# @return [ActivityStream::Definition] the new definitions
|
11
|
+
#
|
12
|
+
def self.define(name, &block)
|
13
|
+
definition = ActivityStream::DefinitionProxy.new(name)
|
14
|
+
definition.instance_eval(&block)
|
15
|
+
ActivityStream::Definition.register(definition)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.new_with_name_and_metadata(name, metadata = {})
|
19
|
+
new(:kind => name.to_s, :metadata => metadata)
|
20
|
+
end
|
21
|
+
|
22
|
+
named_scope :in_reverse_chronological_order, :order => 'occurred_at DESC'
|
23
|
+
|
24
|
+
named_scope :in_chronological_order, :order => 'occurred_at ASC'
|
25
|
+
|
26
|
+
# @param actors [Array] An array of [ActorClass, actor_id] sets
|
27
|
+
# or [ActorClass, [actor_id, actor_id, actor_id...]
|
28
|
+
#
|
29
|
+
named_scope :by_actors, lambda { |actors|
|
30
|
+
if actors.first.is_a?(Array)
|
31
|
+
conditions = actors.map do |(actor_type, actor_id)|
|
32
|
+
%{("activities"."actor_id" = #{actor_id.to_param} AND "activities"."actor_type" = '#{actor_type.to_param}')}
|
33
|
+
end
|
34
|
+
{:conditions => conditions.join(' OR ') }
|
35
|
+
elsif actors.first.is_a?(Class)
|
36
|
+
{:conditions => {:actor_id => actors.last, :actor_type => actors.first.to_param}}
|
37
|
+
else
|
38
|
+
{} # Not sure what to do here.
|
39
|
+
end
|
40
|
+
}
|
41
|
+
|
42
|
+
serialize :metadata, ActivityStream::Metadata
|
43
|
+
|
44
|
+
delegate :template, :icon_path, :to => :definition
|
45
|
+
|
46
|
+
def metadata
|
47
|
+
self[:metadata] ||= ActivityStream::Metadata.new(self[:kind])
|
48
|
+
end
|
49
|
+
|
50
|
+
def metadata=(new_data = {})
|
51
|
+
new_data = new_data.presence || {}
|
52
|
+
occurred_at = new_data.delete(:occurred_at)
|
53
|
+
new_data.each do |key, value|
|
54
|
+
metadata.store(key, value)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def definition
|
59
|
+
ActivityStream::Definition.find_by_name(self[:kind])
|
60
|
+
end
|
61
|
+
|
62
|
+
def kind=(val)
|
63
|
+
write_attribute(:kind, val.to_s)
|
64
|
+
end
|
65
|
+
|
66
|
+
def kind
|
67
|
+
read_attribute(:kind).to_sym
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def ensure_occurred_at_set
|
73
|
+
self.occurred_at ||= Time.now
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -6,8 +6,8 @@ class ActivityStreamGenerator < Rails::Generator::Base
|
|
6
6
|
def manifest
|
7
7
|
record do |m|
|
8
8
|
|
9
|
-
m.directory(File.join('
|
10
|
-
m.template('
|
9
|
+
m.directory(File.join('config','initializers'))
|
10
|
+
m.template('initializer.rb', 'config/initializers/activity_stream.rb')
|
11
11
|
|
12
12
|
user_model = 'app/models/user.rb'
|
13
13
|
if File.exists?(user_model)
|
File without changes
|
@@ -25,23 +25,25 @@ module ActivityStream
|
|
25
25
|
base.extend(ClassMethods)
|
26
26
|
base.class_eval do
|
27
27
|
has_many :activities, :as => :actor
|
28
|
-
activity_stream(:
|
28
|
+
activity_stream(:default, :actors => :followed_actors)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
32
|
# @param name [Symbol] An activity identifer defined by Activity.define
|
33
|
-
def
|
34
|
-
|
33
|
+
def publish_activity(name, metadata = {})
|
34
|
+
activity = ::Activity.new_with_name_and_metadata(name, metadata)
|
35
|
+
self.activities << activity
|
36
|
+
activity
|
35
37
|
end
|
36
38
|
|
37
39
|
# Creates and returns an ActivityStream::Stream for the predefined
|
38
40
|
# list of actors.
|
39
41
|
# @param name [Symbol] The key of a defined activity stream
|
40
|
-
def activity_stream(name)
|
42
|
+
def activity_stream(name = :default)
|
41
43
|
ActivityStream::Stream.new(name, self, self.class.defined_streams[name])
|
42
44
|
end
|
43
|
-
|
44
|
-
def
|
45
|
+
# Override this to change the default actors
|
46
|
+
def followed_actors
|
45
47
|
self.class.all.map{|actor| [actor.class, actor.id]}
|
46
48
|
end
|
47
49
|
|
@@ -2,51 +2,35 @@ require 'active_support/core_ext/array/extract_options'
|
|
2
2
|
|
3
3
|
module ActivityStream
|
4
4
|
|
5
|
-
|
6
|
-
@@definitions ||= []
|
7
|
-
end
|
8
|
-
|
5
|
+
# Defines a type of activity. You don't actually interact with this class directly.
|
9
6
|
class Definition
|
10
7
|
|
11
|
-
attr_reader :name
|
12
|
-
|
13
|
-
# @param
|
14
|
-
|
15
|
-
|
16
|
-
@
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
# `public/images/activity_stream/icons` directory
|
21
|
-
def icon(filename)
|
22
|
-
@icon = filename
|
23
|
-
end
|
24
|
-
|
25
|
-
# @overload metadata
|
26
|
-
# @return [Hash] A hash of defined metadata
|
27
|
-
# @overload metadata(name, opts = {})
|
28
|
-
# @param name [Symbol] the unique name for the metadata attribute
|
29
|
-
# @option opts :default The default value for that metadata
|
30
|
-
def metadata(*args)
|
31
|
-
if args.empty?
|
32
|
-
@metadata
|
33
|
-
else
|
34
|
-
opts = args.extract_options!
|
35
|
-
@metadata[args.first.to_sym] = opts
|
36
|
-
end
|
8
|
+
attr_reader :name, :icon, :metadata, :template
|
9
|
+
|
10
|
+
# @param proxy [ActivityStream::DefinitionProxy] A constructed proxy that
|
11
|
+
# will set the values for this Definition
|
12
|
+
def initialize(proxy)
|
13
|
+
@name = proxy[:name]
|
14
|
+
@metadata = proxy[:metadata] || {}
|
15
|
+
@template = proxy[:template] || 'activity'
|
16
|
+
@icon = proxy[:icon] || 'activity_icon.png'
|
37
17
|
end
|
38
18
|
|
39
|
-
|
40
|
-
|
41
|
-
'activity'
|
19
|
+
def icon_path
|
20
|
+
'activity_stream/icons/%s' % self.icon
|
42
21
|
end
|
43
|
-
|
22
|
+
|
44
23
|
class << self
|
45
24
|
# @param definition [Definition] The definition to be made available
|
46
25
|
# @return [Definition] Returns the registered definition
|
47
26
|
def register(definition)
|
48
|
-
|
49
|
-
definition
|
27
|
+
definition = new(definition) if definition.is_a? DefinitionProxy
|
28
|
+
if definition.is_a? Definition
|
29
|
+
self.all << definition
|
30
|
+
definition
|
31
|
+
else
|
32
|
+
false
|
33
|
+
end
|
50
34
|
end
|
51
35
|
|
52
36
|
# List of registered definitions
|
@@ -58,15 +42,15 @@ module ActivityStream
|
|
58
42
|
# end
|
59
43
|
# ActivityStream::Definition.all
|
60
44
|
def all
|
61
|
-
|
45
|
+
@definitions ||= []
|
62
46
|
end
|
63
47
|
|
64
48
|
# Find a registered definition by its symbolic name
|
65
49
|
# @param name [Symbol] the name to find
|
66
50
|
# @return [ActivityStream::Definition]
|
67
51
|
def find_by_name(name)
|
68
|
-
unless definition = all.find{|
|
69
|
-
raise
|
52
|
+
unless definition = all.find{|definition| definition.name == name.to_sym}
|
53
|
+
raise UndefinedActivity, "Could not find a definition for `#{name}`"
|
70
54
|
else
|
71
55
|
definition
|
72
56
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module ActivityStream
|
2
|
+
|
3
|
+
# Provides a DSL to define an Activity. It is used in Activity.define
|
4
|
+
class DefinitionProxy
|
5
|
+
|
6
|
+
# @param name [Symbol] The name of the activity
|
7
|
+
def initialize(name)
|
8
|
+
@attributes = {
|
9
|
+
:name => name.to_sym,
|
10
|
+
:icon => 'activity_icon.png',
|
11
|
+
:metadata => {},
|
12
|
+
:template => 'activity'
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
# Define the activity's icon
|
17
|
+
# @param filename [String] the icon's name inside of the
|
18
|
+
# `public/images/activity_stream/icons` directory
|
19
|
+
def icon(filename)
|
20
|
+
@attributes.store(:icon, filename)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Define metadata for the activity
|
24
|
+
# @param name [Symbol] the unique name for the metadata attribute
|
25
|
+
# @option opts :default The default value for that metadata
|
26
|
+
# @option opts [Boolean] :required (false) Mark this metadata as required
|
27
|
+
def metadata(*args)
|
28
|
+
opts = args.extract_options!
|
29
|
+
args.each do |name|
|
30
|
+
self.add_metadata(name, opts)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Define a custom template
|
35
|
+
# @param name [String] the name of the template for this Activity.
|
36
|
+
# Should be located in `app/views/activities/*`
|
37
|
+
def template(template_name)
|
38
|
+
@attributes.store(template_name)
|
39
|
+
end
|
40
|
+
|
41
|
+
delegate :[], :to => :@attributes
|
42
|
+
|
43
|
+
def add_metadata(name, opts = {})
|
44
|
+
@attributes[:metadata][name] = opts
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -1,15 +1,56 @@
|
|
1
|
+
require 'active_support/core_ext/module/delegation'
|
2
|
+
require 'active_support/core_ext/object/singleton_class'
|
3
|
+
|
1
4
|
module ActivityStream
|
2
5
|
|
6
|
+
# Storage for an activities metadata.
|
3
7
|
class Metadata
|
4
8
|
|
9
|
+
attr_reader :data
|
10
|
+
|
5
11
|
def initialize(definition_name)
|
6
|
-
|
12
|
+
@definition_name = definition_name
|
13
|
+
@data = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
delegate :merge, :store, :to => :data
|
17
|
+
|
18
|
+
def definition
|
19
|
+
@definition ||= Definition.find_by_name(@definition_name)
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_yaml_properties
|
23
|
+
["@data","@definition_name"]
|
24
|
+
end
|
25
|
+
|
26
|
+
def valid?
|
27
|
+
# TODO: Check definition for required keys, and loop through the
|
28
|
+
# values in @data to see what is missing
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
def method_missing(method_name)
|
33
|
+
case method_name
|
34
|
+
when *definition.metadata.keys
|
35
|
+
@data[method_name]
|
36
|
+
else
|
37
|
+
super
|
38
|
+
end
|
7
39
|
end
|
40
|
+
|
41
|
+
private
|
8
42
|
|
9
|
-
def
|
10
|
-
|
43
|
+
def define_metadata_method(name)
|
44
|
+
self.singleton_class.class_eval do
|
45
|
+
define_method(name) do
|
46
|
+
self.data[name]
|
47
|
+
end
|
48
|
+
define_method(:"#{name.to_s}=") do |value|
|
49
|
+
self.data[name]= value
|
50
|
+
end
|
51
|
+
end
|
11
52
|
end
|
12
53
|
|
13
54
|
end
|
14
55
|
|
15
|
-
end
|
56
|
+
end
|
@@ -12,11 +12,13 @@ module ActivityStream
|
|
12
12
|
@collection = initialize_collection(opts[:actors])
|
13
13
|
end
|
14
14
|
|
15
|
+
# @param reload [Boolean] Return to the database for new activities
|
16
|
+
# @return the activities for the collection of actors
|
15
17
|
def activities(reload = false)
|
16
18
|
if @activities && !reload
|
17
19
|
@activities
|
18
20
|
else
|
19
|
-
@activities = Activity.by_actors(@collection)
|
21
|
+
@activities = ::Activity.by_actors(@collection)
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActivityStream::Metadata do
|
4
|
+
|
5
|
+
let(:metadata) { ActivityStream::Metadata.new(:example_action) }
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
Activity.define(:example_action) do
|
9
|
+
metadata(:one_data)
|
10
|
+
metadata(:two_data)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
after(:each) do
|
15
|
+
ActivityStream::Definition.all.delete(:example_action)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should be initialized with a definition name' do
|
19
|
+
ActivityStream::Metadata.new(:example_action)
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'data storage' do
|
23
|
+
|
24
|
+
it 'should accept new data' do
|
25
|
+
metadata.store(:one_data, 1)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should retrieve previously set data' do
|
29
|
+
metadata.store(:two_data, 2)
|
30
|
+
metadata.data[:two_data].should be(2)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'definition' do
|
36
|
+
|
37
|
+
it 'should return one' do
|
38
|
+
metadata.definition.should be_a(ActivityStream::Definition)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activity_stream
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 3
|
10
|
+
version: 0.0.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Andrew Smith
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-11-
|
18
|
+
date: 2010-11-06 00:00:00 -04:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -81,16 +81,17 @@ files:
|
|
81
81
|
- Rakefile
|
82
82
|
- Readme.md
|
83
83
|
- activity_stream.gemspec
|
84
|
-
- app/models/activity.rb
|
84
|
+
- app/models/activity_stream/activity.rb
|
85
85
|
- generators/activity_stream/activity_stream_generator.rb
|
86
86
|
- generators/activity_stream/lib/insert_commands.rb
|
87
|
-
- generators/activity_stream/templates/
|
87
|
+
- generators/activity_stream/templates/initializer.rb
|
88
88
|
- generators/activity_stream/templates/migration.rb
|
89
89
|
- generators/activity_stream/templates/user.rb
|
90
90
|
- lib/activity_stream.rb
|
91
91
|
- lib/activity_stream/activities_helper.rb
|
92
92
|
- lib/activity_stream/actor.rb
|
93
93
|
- lib/activity_stream/definition.rb
|
94
|
+
- lib/activity_stream/definition_proxy.rb
|
94
95
|
- lib/activity_stream/errors.rb
|
95
96
|
- lib/activity_stream/metadata.rb
|
96
97
|
- lib/activity_stream/stream.rb
|
@@ -149,6 +150,7 @@ files:
|
|
149
150
|
- spec/integration/activity_model_spec.rb
|
150
151
|
- spec/lib/actor_spec.rb
|
151
152
|
- spec/lib/definition_spec.rb
|
153
|
+
- spec/lib/metadata_spec.rb
|
152
154
|
- spec/lib/stream_spec.rb
|
153
155
|
- spec/spec_helper.rb
|
154
156
|
has_rdoc: true
|
@@ -239,5 +241,6 @@ test_files:
|
|
239
241
|
- spec/integration/activity_model_spec.rb
|
240
242
|
- spec/lib/actor_spec.rb
|
241
243
|
- spec/lib/definition_spec.rb
|
244
|
+
- spec/lib/metadata_spec.rb
|
242
245
|
- spec/lib/stream_spec.rb
|
243
246
|
- spec/spec_helper.rb
|
data/app/models/activity.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
class Activity < ActiveRecord::Base
|
2
|
-
|
3
|
-
belongs_to :actor, :polymorphic => true
|
4
|
-
|
5
|
-
# @param name [Symbol] (see ActivityStream::Definition#new)
|
6
|
-
# @return [ActivityStream::Definition] the new definitions
|
7
|
-
#
|
8
|
-
def self.define(name, &block)
|
9
|
-
definition = ActivityStream::Definition.new(name)
|
10
|
-
definition.instance_eval(&block)
|
11
|
-
ActivityStream::Definition.register(definition)
|
12
|
-
end
|
13
|
-
|
14
|
-
named_scope :in_reverse_chronological_order, :order => 'occurred_at DESC'
|
15
|
-
|
16
|
-
named_scope :in_chronological_order, :order => 'occurred_at ASC'
|
17
|
-
|
18
|
-
# @param actors [Array] An array of [ActorClass, actor_id] sets
|
19
|
-
# or [ActorClass, [actor_id, actor_id, actor_id...]
|
20
|
-
#
|
21
|
-
named_scope :by_actors, lambda { |actors|
|
22
|
-
if actors.first.is_a?(Array)
|
23
|
-
conditions = actors.map do |(actor_type, actor_id)|
|
24
|
-
%{("activities"."actor_id" = #{actor_id.to_param} AND "activities"."actor_type" = '#{actor_type.to_param}')}
|
25
|
-
end
|
26
|
-
{:conditions => conditions.join(' OR ') }
|
27
|
-
elsif actors.first.is_a?(Class)
|
28
|
-
{:conditions => {:actor_id => actors.last, :actor_type => actors.first.to_param}}
|
29
|
-
else
|
30
|
-
{} # Not sure what to do here.
|
31
|
-
end
|
32
|
-
}
|
33
|
-
|
34
|
-
serialize :metadata, ActivityStream::Metadata
|
35
|
-
|
36
|
-
delegate :template, :icon, :to => :definition
|
37
|
-
|
38
|
-
def metadata
|
39
|
-
self[:metadata] ||= ActivityStream::Metadata.new(self[:kind])
|
40
|
-
end
|
41
|
-
|
42
|
-
def definition
|
43
|
-
ActivityStream::Definition.find_by_name(self[:kind])
|
44
|
-
end
|
45
|
-
|
46
|
-
end
|