Class: Activr::Timeline
- Inherits:
-
Object
- Object
- Activr::Timeline
- Extended by:
- Forwardable
- Defined in:
- lib/activr/timeline.rb
Overview
With a timeline you can create complex activity feeds.
When creating a Timeline class you specify:
- what model in your application owns that timeline: the `recipient`
- what activities will be displayed in that timeline: the `routes`
Routes can be resolved thanks to:
- a predefined routing declared with routing method, then specified in the :using route setting
- an activity path specified in the :to route setting
- a call on timeline class method specified in the :using route setting
When an activity is routed to a timeline, a Timeline Entry is stored in database and that Timeline Entry contains a copy of the original activity: so Activr uses a “Fanout on write” mecanism to dispatch activities to timelines.
Several callbacks are invoked on timeline instance during the activity handling workflow:
- .should_route_activity? - Returns `false` to skip activity routing
- #should_handle_activity? - Returns `false` to skip routed activity
- #should_store_timeline_entry? - Returns `false` to cancel timeline entry storing
- #will_store_timeline_entry - This is your last chance to modify timeline entry before it is stored
- #did_store_timeline_entry - Called just after timeline entry was stored
Defined Under Namespace
Class Method Summary collapse
-
.have_route?(route_to_check) ⇒ true, false
Check if given route was already defined.
-
.kind ⇒ String
Get timeline class kind.
-
.max_length(value) ⇒ Object
Set maximum length.
-
.recipient(klass) ⇒ Object
Set recipient class.
-
.recipient_id(recipient) ⇒ Object
Get recipient id for given recipient.
-
.route(activity_class, settings = { }) ⇒ Object
Define a route for an activity.
-
.route_for_kind(route_kind) ⇒ Timeline::Route
Get route defined with given kind.
-
.route_for_routing_and_activity(routing_kind, activity_class) ⇒ Timeline::Route
Get route defined with given kind.
-
.routes_for_activity(activity_class) ⇒ Array<Timeline::Route>
Get all routes defined for given activity.
-
.routing(routing_name, settings = { }) {|Activity| ... } ⇒ Object
Creates a predefined routing.
-
.set_kind(forced_kind) ⇒ Object
Set timeline kind.
-
.should_route_activity?(activity) ⇒ true, false
Callback: just before trying to route given activity.
-
.valid_recipient?(recipient) ⇒ true, false
Is it a valid recipient.
Instance Method Summary collapse
-
#count(options = { }) ⇒ Integer
Get total number of timeline entries.
-
#delete(options = { }) ⇒ Object
Delete timeline entries.
-
#did_store_timeline_entry(timeline_entry) ⇒ Object
Callback: just after timeline entry was stored.
-
#dump(options = { }) ⇒ Array<String>
Dump humanization of last timeline entries.
-
#find(limit, options = { }) ⇒ Array<Timeline::Entry>
Find timeline entries by descending timestamp.
-
#handle_activity(activity, route) ⇒ Timeline::Entry
Handle activity.
-
#initialize(rcpt) ⇒ Timeline
constructor
A new instance of Timeline.
-
#recipient ⇒ Object
Get recipient instance.
-
#recipient_id ⇒ Object
Get recipient id.
-
#should_handle_activity?(activity, route) ⇒ true, false
Callback: just before trying to handle routed activity.
-
#should_store_timeline_entry?(timeline_entry) ⇒ true, false
Callback: check if given timeline entry should be stored.
-
#trim! ⇒ Object
Remove old timeline entries.
-
#will_store_timeline_entry(timeline_entry) ⇒ Object
Callback: just before storing timeline entry into timeline.
Constructor Details
#initialize(rcpt) ⇒ Timeline
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
# File 'lib/activr/timeline.rb', line 285 def initialize(rcpt) if self.recipient_class.nil? raise "Missing recipient_class attribute for timeline: #{self}" end if rcpt.is_a?(self.recipient_class) @recipient = rcpt @recipient_id = rcpt.id else @recipient = nil @recipient_id = rcpt end if (@recipient.blank? && @recipient_id.blank?) raise "No recipient provided" end end |
Class Method Details
.have_route?(route_to_check) ⇒ true, false
Check if given route was already defined
133 134 135 |
# File 'lib/activr/timeline.rb', line 133 def have_route?(route_to_check) (route_to_check.timeline_class == self) && !self.route_for_kind(route_to_check.kind).blank? end |
.kind ⇒ String
Kind is inferred from Class name, unless ‘#set_kind` method is used to force a custom value
Get timeline class kind
87 88 89 |
# File 'lib/activr/timeline.rb', line 87 def kind @kind ||= @forced_kind || Activr::Utils.kind_for_class(self, 'timeline') end |
.max_length(value) ⇒ Object
Set maximum length
221 222 223 |
# File 'lib/activr/timeline.rb', line 221 def max_length(value) self.trim_max_length = value end |
.recipient(klass) ⇒ Object
Set recipient class
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'lib/activr/timeline.rb', line 199 def recipient(klass) raise "Routing class already defined: #{self.recipient_class}" unless self.recipient_class.blank? # inject sugar methods klass.class_eval <<-EOS, __FILE__, __LINE__ # fetch latest timeline entries def #{self.kind}(limit, options = { }) Activr.timeline(#{self.name}, self.id).find(limit, options) end # get total number of timeline entries def #{self.kind}_count Activr.timeline(#{self.name}, self.id).count end EOS self.recipient_class = klass end |
.recipient_id(recipient) ⇒ Object
Get recipient id for given recipient
159 160 161 162 163 164 165 166 167 |
# File 'lib/activr/timeline.rb', line 159 def recipient_id(recipient) if self.recipient_class && recipient.is_a?(self.recipient_class) recipient.id elsif Activr.storage.valid_id?(recipient) recipient else raise "Invalid recipient #{recipient.inspect} for timeline #{self}" end end |
.route(activity_class, settings = { }) ⇒ Object
Define a route for an activity
265 266 267 268 269 270 271 |
# File 'lib/activr/timeline.rb', line 265 def route(activity_class, settings = { }) new_route = Activr::Timeline::Route.new(self, activity_class, settings) raise "Route already defined: #{new_route.inspect}" if self.have_route?(new_route) # NOTE: always use a setter on a class_attribute (cf. http://apidock.com/rails/Class/class_attribute) self.routes += [ new_route ] end |
.route_for_kind(route_kind) ⇒ Timeline::Route
Get route defined with given kind
104 105 106 107 108 |
# File 'lib/activr/timeline.rb', line 104 def route_for_kind(route_kind) self.routes.find do |defined_route| (defined_route.kind == route_kind) end end |
.route_for_routing_and_activity(routing_kind, activity_class) ⇒ Timeline::Route
Get route defined with given kind
115 116 117 |
# File 'lib/activr/timeline.rb', line 115 def route_for_routing_and_activity(routing_kind, activity_class) self.route_for_kind(Activr::Timeline::Route.kind_for_routing_and_activity(routing_kind, activity_class.kind)) end |
.routes_for_activity(activity_class) ⇒ Array<Timeline::Route>
Get all routes defined for given activity
123 124 125 126 127 |
# File 'lib/activr/timeline.rb', line 123 def routes_for_activity(activity_class) self.routes.find_all do |defined_route| (defined_route.activity_class == activity_class) end end |
.routing(routing_name, settings = { }) {|Activity| ... } ⇒ Object
Creates a predefined routing
You can either specify a ‘Proc` (with the `:to` setting) to execute or a `block` to yield everytime an activity is routed to that timeline. That `Proc` or that `block` must return an array of recipients or recipients ids.
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/activr/timeline.rb', line 235 def routing(routing_name, settings = { }, &block) routing_name = routing_name.to_s raise "Routing already defined: #{routing_name}" unless self.routings[routing_name].blank? if !block && (!settings[:to] || !settings[:to].is_a?(Proc)) raise "No routing logic provided for #{routing_name}: #{settings.inspect}" end if block raise "It is forbidden to provide a block AND a :to setting" if settings[:to] settings = settings.merge(:to => block) end # NOTE: always use a setter on a class_attribute (cf. http://apidock.com/rails/Class/class_attribute) self.routings = self.routings.merge(routing_name => settings) # create method class_eval <<-EOS, __FILE__, __LINE__ # eg: actor_follower(activity) def self.#{routing_name}(activity) self.routings['#{routing_name}'][:to].call(activity) end EOS end |
.set_kind(forced_kind) ⇒ Object
Default kind is inferred from class name
Set timeline kind
96 97 98 |
# File 'lib/activr/timeline.rb', line 96 def set_kind(forced_kind) @forced_kind = forced_kind.to_s end |
.should_route_activity?(activity) ⇒ true, false
MAY be overriden by child class
Callback: just before trying to route given activity
143 144 145 |
# File 'lib/activr/timeline.rb', line 143 def should_route_activity?(activity) true end |
Instance Method Details
#count(options = { }) ⇒ Integer
Get total number of timeline entries
358 359 360 |
# File 'lib/activr/timeline.rb', line 358 def count( = { }) Activr.storage.count_timeline(self, ) end |
#delete(options = { }) ⇒ Object
Delete timeline entries
380 381 382 |
# File 'lib/activr/timeline.rb', line 380 def delete( = { }) Activr.storage.delete_timeline(self, ) end |
#did_store_timeline_entry(timeline_entry) ⇒ Object
MAY be overriden by child class
Callback: just after timeline entry was stored
435 436 437 |
# File 'lib/activr/timeline.rb', line 435 def did_store_timeline_entry(timeline_entry) # NOOP end |
#dump(options = { }) ⇒ Array<String>
Dump humanization of last timeline entries
368 369 370 371 372 373 374 |
# File 'lib/activr/timeline.rb', line 368 def dump( = { }) = .dup limit = .delete(:nb) || 100 self.find(limit).map{ |tl_entry| tl_entry.humanize() } end |
#find(limit, options = { }) ⇒ Array<Timeline::Entry>
Find timeline entries by descending timestamp
349 350 351 |
# File 'lib/activr/timeline.rb', line 349 def find(limit, = { }) Activr.storage.find_timeline(self, limit, ) end |
#handle_activity(activity, route) ⇒ Timeline::Entry
Handle activity
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
# File 'lib/activr/timeline.rb', line 322 def handle_activity(activity, route) # create timeline entry klass = Activr.registry.class_for_timeline_entry(self.kind, route.kind) timeline_entry = klass.new(self, route.routing_kind, activity) # store with callbacks if self.should_store_timeline_entry?(timeline_entry) self.will_store_timeline_entry(timeline_entry) # store timeline_entry.store! self.did_store_timeline_entry(timeline_entry) # trim timeline self.trim! end timeline_entry._id.blank? ? nil :timeline_entry end |
#recipient ⇒ Object
Get recipient instance
306 307 308 |
# File 'lib/activr/timeline.rb', line 306 def recipient @recipient ||= self.recipient_class.find(@recipient_id) end |
#recipient_id ⇒ Object
Get recipient id
313 314 315 |
# File 'lib/activr/timeline.rb', line 313 def recipient_id @recipient_id ||= @recipient.id end |
#should_handle_activity?(activity, route) ⇒ true, false
MAY be overriden by child class
Callback: just before trying to handle routed activity
407 408 409 |
# File 'lib/activr/timeline.rb', line 407 def should_handle_activity?(activity, route) true end |
#should_store_timeline_entry?(timeline_entry) ⇒ true, false
MAY be overriden by child class
Callback: check if given timeline entry should be stored
417 418 419 |
# File 'lib/activr/timeline.rb', line 417 def should_store_timeline_entry?(timeline_entry) true end |
#trim! ⇒ Object
Remove old timeline entries
385 386 387 388 389 390 391 392 393 |
# File 'lib/activr/timeline.rb', line 385 def trim! # check if trimming is needed if (self.trim_max_length > 0) && (self.count > self.trim_max_length) last_tle = self.find(1, :skip => self.trim_max_length - 1).first if last_tle self.delete(:before => last_tle.activity.at) end end end |
#will_store_timeline_entry(timeline_entry) ⇒ Object
MAY be overriden by child class
Callback: just before storing timeline entry into timeline
426 427 428 |
# File 'lib/activr/timeline.rb', line 426 def will_store_timeline_entry(timeline_entry) # NOOP end |