lifestreamable 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ === 0.0.1 2010-05-19
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/Manifest.txt ADDED
@@ -0,0 +1,11 @@
1
+ History.txt
2
+ Manifest.txt
3
+ PostInstall.txt
4
+ README.rdoc
5
+ Rakefile
6
+ lib/lifestreamable.rb
7
+ script/console
8
+ script/destroy
9
+ script/generate
10
+ test/test_helper.rb
11
+ test/test_lifestreamable.rb
data/PostInstall.txt ADDED
@@ -0,0 +1,7 @@
1
+
2
+ For more information on lifestreamable, see http://lifestreamable.rubyforge.org
3
+
4
+ NOTE: Change this information in PostInstall.txt
5
+ You can also delete it if you don't want it.
6
+
7
+
data/README.rdoc ADDED
@@ -0,0 +1,103 @@
1
+ = lifestreamable
2
+
3
+ * github.com/benoitgoyette/lifestreamable
4
+
5
+ == DESCRIPTION:
6
+
7
+ Lifestreamable is a rails gem that allows social network life lifestream operations. A lifestream is a series of events that occured and that are related to an owner.
8
+ It has been designed to collect data upfront in model observers to minimize the number of request done at display time. the goal being that if the lifestream dislays several types of data over several different models, then only a single query will be run to get all the data to display instead of querying all data for each model. this radiaclly cuts down on display time.
9
+ This is a port to a gem of the lifestream libraries that have been designed for the sports social network legrandclub.rds.ca
10
+
11
+ == FEATURES/PROBLEMS:
12
+
13
+ TODO:
14
+ add support for pagination.
15
+ add support for delayed jobs.
16
+ port to rails 3.0
17
+ write the tests
18
+ complete the doc on which options are available for lifestreamable and lifestreamed
19
+
20
+ == SYNOPSIS:
21
+
22
+ Ths lifestream modules is made up of 2 mixins, the lifestreamable, and lifestreamed modules.
23
+ The lifestreamed module is included for models that own events, while the lifestreamable module is included on each model that triggers the event.
24
+
25
+ for example, a user can write posts and comments, we want to report in the user's lifestream that the user has written posts and comments.
26
+
27
+
28
+ defining the owner class
29
+ class User < ActiveRecord::Base
30
+ lifestreamed
31
+ end
32
+
33
+ defining the event classes
34
+ class Post < ActiveRecord::Base
35
+ belongs_to :user
36
+ has_many :comments
37
+ lifestreamable :on=>[:create, :update, :destroy], data=>:get_data, :owner=>:user
38
+
39
+ def get_data # this method must return a data structure that is serializable by YAML
40
+ {
41
+ :user=>{:firstname=>self.user.firstname, :lastname=>self.user.lastname},
42
+ :post=>{:title=>self.title}
43
+ }
44
+ end
45
+ end
46
+
47
+ class Comment < ActiveRecord::Base
48
+ belongs_to :user
49
+ belongs_to :post
50
+ # another way to get the data is through a Proc
51
+ lifestreamable :on=>[:create, :update, :destroy], :owner=>:user, data=> lambda {|model|
52
+ {
53
+ :user=>{:firstname=>model.user.firstname, :lastname=>model.user.lastname},
54
+ :post=>{:title=>model.post.title},
55
+ :comment=>{:body=>model.body}
56
+ }
57
+ }
58
+ end
59
+
60
+ get the lifestream from the owner
61
+ user=User.first
62
+
63
+ # get the lifestream for the user
64
+ lifestream = user.lifestream #=> returns an array of Lifestreamable::Lifesteam instances
65
+
66
+ #get the data that was stored
67
+ data = lifestream.first.object_data
68
+
69
+
70
+
71
+ == REQUIREMENTS:
72
+
73
+ * YAML
74
+
75
+ == INSTALL:
76
+
77
+ * sudo gem install lifestreamable
78
+
79
+
80
+ == LICENSE:
81
+
82
+ (The MIT License)
83
+
84
+ Copyright (c) 2010 Benoit Goyette
85
+
86
+ Permission is hereby granted, free of charge, to any person obtaining
87
+ a copy of this software and associated documentation files (the
88
+ 'Software'), to deal in the Software without restriction, including
89
+ without limitation the rights to use, copy, modify, merge, publish,
90
+ distribute, sublicense, and/or sell copies of the Software, and to
91
+ permit persons to whom the Software is furnished to do so, subject to
92
+ the following conditions:
93
+
94
+ The above copyright notice and this permission notice shall be
95
+ included in all copies or substantial portions of the Software.
96
+
97
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
98
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
99
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
100
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
101
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
102
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
103
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ require 'rubygems'
2
+ gem 'hoe', '>= 2.1.0'
3
+ require 'hoe'
4
+ require 'fileutils'
5
+ require './lib/lifestreamable'
6
+
7
+ # Generate all the Rake tasks
8
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
9
+ # $hoe = Hoe.spec 'lifestreamable' do
10
+ # self.developer 'FIXME full name', 'FIXME email'
11
+ # self.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
12
+ # self.rubyforge_name = self.name # TODO this is default value
13
+ # # self.extra_deps = [['activesupport','>= 2.0.2']]
14
+ #
15
+ # end
16
+
17
+ Dir['tasks/**/*.rake'].each { |t| load t }
18
+
19
+ # TODO - want other tests/tasks run by default? Add them to the list
20
+ # remove_task :default
21
+ # task :default => [:spec, :features]
@@ -0,0 +1,20 @@
1
+ class LifestreamableMigrationGenerator < Rails::Generator::Base
2
+ default_options :skip_migration => false
3
+
4
+ def manifest
5
+ record do |m|
6
+ unless options[:skip_migration]
7
+ m.migration_template "migration.rb", 'db/migrate', :migration_file_name => "create_lifestreams"
8
+ end
9
+ end
10
+ end
11
+
12
+ protected
13
+
14
+ def add_options!(opt)
15
+ opt.separator ''
16
+ opt.separator 'Options:'
17
+ opt.on("--skip-migration", "Don't generate a migration") { |v| options[:skip_migration] = v }
18
+ end
19
+
20
+ end
@@ -0,0 +1,21 @@
1
+ class CreateLifestreams < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :lifestreams do |t|
4
+ t.string :owner_type
5
+ t.integer :owner_id
6
+ t.string :stream_type
7
+ t.string :reference_type
8
+ t.integer :reference_id
9
+ t.text :object_data_hash
10
+ t.timestamps
11
+ end
12
+
13
+ add_index(:lifestreams, [:owner_id, :owner_type], :name=>'lifestreams_profil_id' )
14
+ add_index(:lifestreams, :stream_type, :name=>'lifestreams_stream_type' )
15
+ add_index(:lifestreams, [:reference_id, :reference_type], :name=>'lifestreams_stream_object' )
16
+ end
17
+
18
+ def self.down
19
+ drop_table :lifestreams
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ module Lifestreamable
2
+ class CreateObserver < Lifestreamable::Observer
3
+ observe :"lifestreamable/dummy"
4
+ def after_create(model)
5
+ if model.lifestreamable?
6
+ Lifestreamable::Lifestreamer.push model.get_action_instead_of(:create), model.get_payload
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module Lifestreamable
2
+ class DestroyObserver < Lifestreamable::Observer
3
+ observe :"lifestreamable/dummy"
4
+ def before_destroy(model)
5
+ if model.lifestreamable?
6
+ Lifestreamable::Lifestreamer.push model.get_action_instead_of(:destroy), model.get_payload
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,108 @@
1
+ module Lifestreamable
2
+ class Lifestream < ActiveRecord::Base
3
+ DEFAULT_LIMIT_PER_PAGE = 25
4
+ DEFAULT_PAGE = 0
5
+
6
+ belongs_to :owner, :polymorphic => true
7
+ belongs_to :reference, :polymorphic => true
8
+
9
+
10
+ def object_data
11
+ YAML.load(self.object_data_hash)
12
+ end
13
+ alias_method :object_hash, :object_data
14
+
15
+ class << self
16
+ #
17
+ # CREATION DU LIFESTREAM
18
+ #
19
+ def process(action, struct)
20
+ # put explicitly the actions accepted
21
+ case action
22
+ when :create
23
+ create get_payload(struct)
24
+ when :update
25
+ l = Lifestream.find_by_reference_type_and_reference_id_and_stream_type(struct.reference_type, struct.reference_id, struct.stream_type)
26
+ l.update_attributes get_payload(struct) unless l.blank?
27
+ when :destroy
28
+ l = Lifestream.find_by_reference_type_and_reference_id_and_stream_type(struct.reference_type, struct.reference_id, struct.stream_type)
29
+ l.destroy unless l.blank?
30
+ else
31
+ raise LifestreamableException.new "unknown action #{action} in Lifestreamable::Lifestream.process"
32
+ end
33
+ end
34
+
35
+
36
+ # FINDERS
37
+
38
+ def find_by_reference_type_and_reference_id_and_stream_type(reference_type, reference_id, stream_type)
39
+ find(:last, :conditions=>['reference_type = ? and reference_id = ? and stream_type = ?', reference_type, reference_id, stream_type])
40
+ end
41
+
42
+ def find_lifestream_for_owner(owner, *options)
43
+ opts = get_options_for_find owner, options[0]
44
+ results = find :all, opts
45
+ end
46
+
47
+ def find_lifestream_for_group(owner, group, *options)
48
+ opts = get_options_for_group_find owner, group, options[0]
49
+ results = find :all, opts
50
+ end
51
+
52
+ protected
53
+
54
+ def get_options_for_find(owner, options)
55
+ opt = options.blank? ? {} : options.to_options
56
+ set_basic_options!(opt)
57
+ cond = get_condition_for_find(owner)
58
+ opt[:conditions] = if opt[:conditions].blank?
59
+ cond
60
+ else
61
+ cond[0]+= " AND #{opt[:conditions][0]}"
62
+ cond += opt[:conditions][1..-1]
63
+ cond
64
+ end
65
+ opt
66
+ end
67
+
68
+ def get_options_for_group_find(owner, group, options)
69
+ opt = options.blank? ? {} : options.to_options
70
+ set_basic_options!(opt)
71
+ cond = get_condition_for_group_find(owner, group)
72
+ opt[:conditions] = if opt[:conditions].blank?
73
+ cond
74
+ else
75
+ cond[0]+= " AND #{opt[:conditions][0]}"
76
+ cond += opt[:conditions][1..-1]
77
+ cond
78
+ end
79
+ opt
80
+ end
81
+
82
+ def set_basic_options!(opt)
83
+ opt[:limit]=opt[:per_page] ? opt.delete(:per_page) : DEFAULT_LIMIT_PER_PAGE
84
+ opt[:offset]=opt[:page] ? (opt.delete(:page)-1)*opt[:limit] : DEFAULT_PAGE
85
+ opt[:order]=opt[:order] ? opt[:order] : 'id desc'
86
+ end
87
+
88
+ def get_condition_for_find(owner)
89
+ ['owner_type = ? and owner_id = ? ', owner.class.name, owner.id]
90
+ end
91
+
92
+ def get_condition_for_group_find(owner, group)
93
+ ['owner_type = ? and owner_id in (?) ', owner.class.name, [owner.id] + group]
94
+ end
95
+
96
+ def get_payload(struct)
97
+ hash_from_struct(struct)
98
+ end
99
+
100
+ def hash_from_struct(struct)
101
+ h = {}
102
+ struct.each_pair {|k,v| h[k.to_sym]=v}
103
+ h
104
+ end
105
+
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,194 @@
1
+ # Pour le lifestream, on ajoute une methode a ActiveRecord::Base
2
+ # pour savoir si on doit effacer une entree du lifestream a la
3
+ # place de faire un update.
4
+ # comme dans le cas de detail.youtube_username, si on efface
5
+ # la valeur, on veut effacer l'entree dans le lifestream.
6
+ # Meme chose pour l'insert, si on change le youtube user name,
7
+ # on veut que ca insere une nouvelle rangee dans le lifestream.
8
+
9
+ module Lifestreamable
10
+ Struct.new('LifestreamData', :reference_type, :reference_id, :owner_type, :owner_id, :stream_type, :object_data_hash)
11
+ TRUE_REGEX = /^[tT][rR][uU][eE]$/
12
+ FALSE_REGEX = /^[fF][aA][lL][sS][eE]$/
13
+
14
+ def self.included(base)
15
+ base.extend LifestreamableClassMethods
16
+ end
17
+
18
+ module LifestreamableClassMethods
19
+ @@lifestream_options={}
20
+
21
+ def lifestream_options
22
+ @@lifestream_options
23
+ end
24
+
25
+ def lifestreamable(options)
26
+ include LifestreamableInstanceMethods
27
+
28
+ options.to_options
29
+ options[:on].each do |option_on|
30
+ case option_on
31
+ when :update
32
+ Lifestreamable::UpdateObserver.instance.add_class_observer self.class_name.constantize
33
+ when :create
34
+ Lifestreamable::CreateObserver.instance.add_class_observer self.class_name.constantize
35
+ when :destroy
36
+ Lifestreamable::DestroyObserver.instance.add_class_observer self.class_name.constantize
37
+ else
38
+ raise Exception.new("option \"#{option_on}\" is not supported for Lifestreamable")
39
+ end
40
+ end
41
+ @@lifestream_options = {:data=>options[:data], :on=>options[:on], :type=>options[:type], :owner=>options[:owner], :when=>options[:when], :filter=>options[:filter],
42
+ :destroy_instead_of_update=>options[:destroy_instead_of_update], :create_instead_of_update=>options[:create_instead_of_update],
43
+ :create_instead_of_destroy=>options[:create_instead_of_destroy], :update_instead_of_destroy=>options[:update_instead_of_destroy]}
44
+ end
45
+
46
+ def filter(lifestream)
47
+ puts "in lifestreamable.filter"
48
+ option = self.lifestream_options[:filter]
49
+ lifestream = case option
50
+ when Proc
51
+ option.call(self, lifestream)
52
+ when String, Symbol
53
+ send(option.to_s, lifestream) if respond_to?(option.to_s)
54
+ else
55
+ lifestream
56
+ end
57
+ lifestream
58
+ end
59
+
60
+ end
61
+
62
+ module LifestreamableInstanceMethods
63
+ def lifestream_options
64
+ self.class.lifestream_options
65
+ end
66
+
67
+ def lifestreamable?
68
+ case self.lifestream_options[:when]
69
+ when NilClass, TrueClass, :true, TRUE_REGEX
70
+ true
71
+ when FalseClass, :false, FALSE_REGEX
72
+ false
73
+ when Proc
74
+ self.lifestream_options[:when].call(self)
75
+ when String, Symbol
76
+ send(self.lifestream_options[:when].to_s)
77
+ end
78
+ end
79
+
80
+ def get_payload
81
+ reference_type, reference_id = get_reference
82
+ owner_type, owner_id = get_owner
83
+ stream_type = get_stream_type
84
+ data = get_lifestream_data.to_yaml
85
+ Struct::LifestreamData.new reference_type, reference_id, owner_type, owner_id, stream_type, data
86
+ end
87
+
88
+ def get_action_instead_of(action)
89
+ case action
90
+ when :create
91
+ :create
92
+ when :update
93
+ if test_instead_option(lifestream_options[:create_instead_of_update])
94
+ :create
95
+ elsif test_instead_option(lifestream_options[:destroy_instead_of_update])
96
+ :destroy
97
+ else
98
+ :update
99
+ end
100
+ when :destroy
101
+ if test_instead_option(lifestream_options[:create_instead_of_destroy])
102
+ :create
103
+ elsif test_instead_option(lifestream_options[:destroy_instead_of_destroy])
104
+ :update
105
+ else
106
+ :destroy
107
+ end
108
+ else
109
+ raise LifestreamableException.new("The action #{action.to_s} is not a valid type of action")
110
+ end
111
+ end
112
+
113
+ protected
114
+ # if the option[:when] is not defined, then it's considered true
115
+ def get_reference
116
+ [self.class.name, self.id]
117
+ end
118
+
119
+ def get_owner
120
+ return_vals = case self.lifestream_options[:owner]
121
+ when Proc
122
+ self.lifestream_options[:owner].call(self)
123
+ when String, Symbol
124
+ send(self.lifestream_options[:owner].to_s)
125
+ else
126
+ raise LifestreamableException.new("The lifestreamable :owner option is invalid")
127
+ end
128
+
129
+ case return_vals
130
+ when NilClass
131
+ LifestreamableException.new("The lifestreamable :owner option Proc must return either an ActiveRecord::Base subclass or an array of [class_name, id]")
132
+ when Array
133
+ if return_vals.length == 1
134
+ if return_vals.is_a?(ActiveRecord::Base)
135
+ return [return_vals.class.name, return_vals.id]
136
+ else
137
+ LifestreamableException.new("The lifestreamable :owner option Proc evaluation returned only 1 value, but it's not an ActiveRecord::Base")
138
+ end
139
+ else
140
+ return_vals[0,2]
141
+ end
142
+ when ActiveRecord::Base
143
+ return [return_vals.class.name, return_vals.id]
144
+ end
145
+ end
146
+
147
+ def get_stream_type
148
+ case self.lifestream_options[:type]
149
+ when NilClass
150
+ self.class.name.underscore
151
+ when Proc
152
+ self.lifestream_options[:type].call(self)
153
+ when String, Symbol
154
+ if self.respond_to?(self.lifestream_options[:type].to_s)
155
+ send(self.lifestream_options[:type].to_s)
156
+ else
157
+ self.lifestream_options[:type].to_s
158
+ end
159
+ else
160
+ raise LifestreamableException.new("The lifestreamable :type option is invalid")
161
+ end
162
+ end
163
+
164
+ def get_lifestream_data
165
+ case self.lifestream_options[:data]
166
+ when Proc
167
+ self.lifestream_options[:data].call(self)
168
+ when String, Symbol
169
+ send(self.lifestream_options[:data].to_s)
170
+ else
171
+ raise LifestreamableException.new("The lifestreamable :data option is invalid")
172
+ end
173
+ end
174
+
175
+ private
176
+ def test_instead_option(option)
177
+ case option
178
+ when NilClass, FalseClass, :false, FALSE_REGEX
179
+ false
180
+ when TrueClass, :true, TRUE_REGEX
181
+ true
182
+ when Proc
183
+ option.call(self)
184
+ when String, Symbol
185
+ send(option.to_s)
186
+ end == true # make sure we return true/false
187
+ end
188
+ end
189
+ end
190
+
191
+ ActiveRecord::Base.observers << :"lifestreamable/update_observer"
192
+ ActiveRecord::Base.observers << :"lifestreamable/create_observer"
193
+ ActiveRecord::Base.observers << :"lifestreamable/destroy_observer"
194
+ ActiveRecord::Base.send(:include, Lifestreamable)
@@ -0,0 +1,88 @@
1
+ module Lifestreamable
2
+ module Lifestreamed
3
+ def self.included(base)
4
+ base.extend LifestreamedClassMethods
5
+ end
6
+
7
+ module LifestreamedClassMethods
8
+ @@lifestreamed_options={}
9
+
10
+ def lifestreamed_options
11
+ @@lifestreamed_options
12
+ end
13
+
14
+ def lifestreamed(*options)
15
+ include LifestreamedInstanceMethods
16
+ @@lifestreamed_options = options[0].blank? ? {} : options[0].to_options.clone if options[0]
17
+ end
18
+
19
+ end
20
+
21
+ module LifestreamedInstanceMethods
22
+ def lifestreamed_options
23
+ self.class.lifestreamed_options
24
+ end
25
+
26
+ def lifestream(*options)
27
+ opt, do_filter = get_options_and_filter(options[0])
28
+ lifestream = Lifestreamable::Lifestream.find_lifestream_for_owner(self, opt)
29
+ do_filter ? filter(lifestream) : lifestream
30
+ end
31
+
32
+ def group_lifestream(group, *options)
33
+ opt, do_filter = get_options_and_filter(options[0])
34
+ lifestream = Lifestreamable::Lifestream.find_lifestream_for_group(self, group, opt)
35
+ do_filter ? filter(lifestream) : lifestream
36
+ end
37
+
38
+ private
39
+
40
+ def get_options_and_filter(options)
41
+ opt = options.blank? ? {} : options.to_options
42
+ order_opt = get_order_option(opt.has_key?(:order) ? opt[:order] : self.lifestreamed_options[:order] )
43
+ opt[:order]= order_opt unless order_opt.blank?
44
+ filter_option = opt.has_key?(:filter) ? opt.delete(:filter) : self.lifestreamed_options[:filter]
45
+ do_filter = get_filter_option( filter_option )
46
+ [opt, do_filter]
47
+ end
48
+
49
+ def get_filter_option(option)
50
+ puts "getting filter option"
51
+ case option
52
+ when NilClass, FalseClass, :false, Lifestreamable::FALSE_REGEX
53
+ false
54
+ when TrueClass, :true, Lifestreamable::TRUE_REGEX
55
+ true
56
+ when Proc # make sure we return true/false
57
+ option.call(self) == true
58
+ when String, Symbol # make sure we return true/false
59
+ send(option.to_s) == true
60
+ end
61
+ end
62
+
63
+ def get_order_option(option)
64
+ case option
65
+ when Proc
66
+ option.call(self)
67
+ when String, Symbol
68
+ if self.respond_to?(option.to_s)
69
+ send(option.to_s)
70
+ else
71
+ option.to_s
72
+ end
73
+ end
74
+ end
75
+
76
+ def filter(lifestream)
77
+ lf = lifestream.clone
78
+ types = lf.collect {|l| l.reference_type}
79
+ types.uniq!
80
+ types.each {|l|
81
+ lf = l.constantize.filter(lf) if l.constantize.respond_to?('filter')}
82
+ lf
83
+ end
84
+
85
+ end
86
+ end
87
+ end
88
+ ActiveRecord::Base.send(:include, Lifestreamable::Lifestreamed)
@@ -0,0 +1,26 @@
1
+ module Lifestreamable
2
+ module Lifestreamer
3
+ @@stack=[]
4
+ def self.push(action, lifestream_struct)
5
+ @@stack.push [action, lifestream_struct]
6
+ @@stack.uniq!
7
+ end
8
+ def self.generate_lifestream
9
+ while (lifestream_entry=@@stack.shift)
10
+ begin
11
+ Lifestream.process(lifestream_entry[0], lifestream_entry[1])
12
+ rescue Exception => e
13
+ puts e.message, e.backtrace
14
+ # TODO PUT SOMETHING HERE!!!
15
+ end
16
+ end
17
+ end
18
+ def self.clear
19
+ @@stack.clear
20
+ end
21
+ def self.inspect
22
+ @@stack.inspect
23
+ end
24
+ end
25
+ end
26
+ ActionController::Base.send(:after_filter, "Lifestreamable::Lifestreamer.generate_lifestream")
@@ -0,0 +1,20 @@
1
+ module Lifestreamable
2
+ class Observer < ActiveRecord::Observer
3
+
4
+ def add_class_observer(klass)
5
+ self.add_observer!(klass)
6
+ end
7
+
8
+ end
9
+ class Dummy
10
+ include Observable
11
+ class << self
12
+ def add_observer(*args)
13
+ end
14
+ end
15
+ end
16
+
17
+ end
18
+
19
+ class LifestreamableException < Exception
20
+ end
@@ -0,0 +1,11 @@
1
+ module Lifestreamable
2
+ class UpdateObserver < Lifestreamable::Observer
3
+ observe :"lifestreamable/dummy"
4
+ def after_update(model)
5
+ if model.lifestreamable?
6
+ Lifestreamable::Lifestreamer.push model.get_action_instead_of(:update), model.get_payload
7
+ end
8
+ end
9
+ end
10
+ end
11
+
@@ -0,0 +1,9 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require File.join(File.dirname(__FILE__),'lifestreamable/lifestreamable')
5
+ require File.join(File.dirname(__FILE__),'lifestreamable/lifestreamed')
6
+
7
+ module Lifestreamable
8
+ VERSION = '0.0.2'
9
+ end
@@ -0,0 +1,52 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{lifestreamable}
5
+ s.version = "0.0.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Benoit Goyette"]
9
+ s.date = %q{2010-05-19}
10
+ s.description = %q{library to perform social network like lifetstream functions, this is the code used on the social network http://legrandclub.rds.ca}
11
+ s.email = %q{benoit.goyette@gmail.com}
12
+ s.files = ["History.txt",
13
+ "Manifest.txt",
14
+ "PostInstall.txt",
15
+ "README.rdoc",
16
+ "Rakefile",
17
+ "generators/lifestreamable_migration/lifestreamable_migration_generator.rb",
18
+ "generators/lifestreamable_migration/templates/migration.rb",
19
+ "lib/lifestreamable/create_observer.rb",
20
+ "lib/lifestreamable/destroy_observer.rb",
21
+ "lib/lifestreamable/lifestream.rb",
22
+ "lib/lifestreamable/lifestreamable.rb",
23
+ "lib/lifestreamable/lifestreamed.rb",
24
+ "lib/lifestreamable/lifestreamer.rb",
25
+ "lib/lifestreamable/observer.rb",
26
+ "lib/lifestreamable/update_observer.rb",
27
+ "lib/lifestreamable.rb",
28
+ "lifestreamable.gemspec",
29
+ "script/console",
30
+ "script/destroy",
31
+ "script/generate",
32
+ "test/test_helper.rb",
33
+ "test/test_lifestreamable.rb"]
34
+ s.homepage = %q{http://lab.pheromone.ca}
35
+ s.rdoc_options = ["--exclude", "."]
36
+ s.require_paths = ["lib"]
37
+ s.rubyforge_project = %q{lifestreamable}
38
+ s.rubygems_version = %q{1.3.1}
39
+ s.summary = %q{a rails plugin to collect and report user social actions.}
40
+
41
+
42
+ # if s.respond_to? :specification_version then
43
+ # current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
44
+ # s.specification_version = 3
45
+ # if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
46
+ # else
47
+ # end
48
+ # else
49
+ # end
50
+ end
51
+
52
+
data/script/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/lifestreamable.rb'}"
9
+ puts "Loading lifestreamable gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,3 @@
1
+ require 'stringio'
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/../lib/lifestreamable'
@@ -0,0 +1,13 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestLifestreamable < Test::Unit::TestCase
4
+
5
+ def setup
6
+ end
7
+
8
+ def test_truth
9
+ assert true
10
+ end
11
+
12
+
13
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lifestreamable
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Benoit Goyette
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-05-19 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: library to perform social network like lifetstream functions, this is the code used on the social network http://legrandclub.rds.ca
22
+ email: benoit.goyette@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - History.txt
31
+ - Manifest.txt
32
+ - PostInstall.txt
33
+ - README.rdoc
34
+ - Rakefile
35
+ - generators/lifestreamable_migration/lifestreamable_migration_generator.rb
36
+ - generators/lifestreamable_migration/templates/migration.rb
37
+ - lib/lifestreamable/create_observer.rb
38
+ - lib/lifestreamable/destroy_observer.rb
39
+ - lib/lifestreamable/lifestream.rb
40
+ - lib/lifestreamable/lifestreamable.rb
41
+ - lib/lifestreamable/lifestreamed.rb
42
+ - lib/lifestreamable/lifestreamer.rb
43
+ - lib/lifestreamable/observer.rb
44
+ - lib/lifestreamable/update_observer.rb
45
+ - lib/lifestreamable.rb
46
+ - lifestreamable.gemspec
47
+ - script/console
48
+ - script/destroy
49
+ - script/generate
50
+ - test/test_helper.rb
51
+ - test/test_lifestreamable.rb
52
+ has_rdoc: true
53
+ homepage: http://lab.pheromone.ca
54
+ licenses: []
55
+
56
+ post_install_message:
57
+ rdoc_options:
58
+ - --exclude
59
+ - .
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ segments:
67
+ - 0
68
+ version: "0"
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ requirements: []
77
+
78
+ rubyforge_project: lifestreamable
79
+ rubygems_version: 1.3.6
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: a rails plugin to collect and report user social actions.
83
+ test_files: []
84
+