activity_engine 0.0.2

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.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +23 -0
  5. data/Guardfile +10 -0
  6. data/LICENSE.txt +17 -0
  7. data/README.md +39 -0
  8. data/Rakefile +11 -0
  9. data/TODO.md +24 -0
  10. data/activity_engine.gemspec +31 -0
  11. data/app/assets/images/activity_engine/.gitkeep +0 -0
  12. data/app/assets/javascripts/activity_engine/application.js +15 -0
  13. data/app/assets/stylesheets/activity_engine/application.css +13 -0
  14. data/app/controllers/activity_engine/application_controller.rb +4 -0
  15. data/app/helpers/activity_engine/application_helper.rb +4 -0
  16. data/app/models/activity_engine/activity.rb +28 -0
  17. data/app/views/layouts/activity_engine/application.html.erb +14 -0
  18. data/config/routes.rb +2 -0
  19. data/db/migrate/20130722162331_create_activity_engine_activities.rb +13 -0
  20. data/lib/activity_engine/activity_builder.rb +45 -0
  21. data/lib/activity_engine/activity_data_structure.rb +10 -0
  22. data/lib/activity_engine/context_builder.rb +40 -0
  23. data/lib/activity_engine/engine.rb +17 -0
  24. data/lib/activity_engine/exceptions.rb +7 -0
  25. data/lib/activity_engine/version.rb +3 -0
  26. data/lib/activity_engine.rb +14 -0
  27. data/lib/generators/activity_engine/install_generator.rb +19 -0
  28. data/lib/generators/activity_engine/register_generator.rb +28 -0
  29. data/lib/generators/activity_engine/templates/activity_engine_config.rb +6 -0
  30. data/lib/tasks/activity_engine_tasks.rake +4 -0
  31. data/script/rails +8 -0
  32. data/spec/dummy/README.rdoc +261 -0
  33. data/spec/dummy/Rakefile +7 -0
  34. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  35. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  36. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  37. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  38. data/spec/dummy/app/mailers/.gitkeep +0 -0
  39. data/spec/dummy/app/models/.gitkeep +0 -0
  40. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  41. data/spec/dummy/config/application.rb +59 -0
  42. data/spec/dummy/config/boot.rb +10 -0
  43. data/spec/dummy/config/database.yml +25 -0
  44. data/spec/dummy/config/environment.rb +5 -0
  45. data/spec/dummy/config/environments/development.rb +37 -0
  46. data/spec/dummy/config/environments/production.rb +67 -0
  47. data/spec/dummy/config/environments/test.rb +37 -0
  48. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  49. data/spec/dummy/config/initializers/inflections.rb +15 -0
  50. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  51. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  52. data/spec/dummy/config/initializers/session_store.rb +8 -0
  53. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  54. data/spec/dummy/config/locales/en.yml +5 -0
  55. data/spec/dummy/config/routes.rb +4 -0
  56. data/spec/dummy/config.ru +4 -0
  57. data/spec/dummy/db/schema.rb +28 -0
  58. data/spec/dummy/lib/assets/.gitkeep +0 -0
  59. data/spec/dummy/log/.gitkeep +0 -0
  60. data/spec/dummy/public/404.html +26 -0
  61. data/spec/dummy/public/422.html +26 -0
  62. data/spec/dummy/public/500.html +25 -0
  63. data/spec/dummy/public/favicon.ico +0 -0
  64. data/spec/dummy/script/rails +6 -0
  65. data/spec/lib/activity_engine/activity_builder_spec.rb +54 -0
  66. data/spec/lib/activity_engine/activity_data_structure_spec.rb +10 -0
  67. data/spec/lib/activity_engine/context_builder_spec.rb +83 -0
  68. data/spec/lib/activity_engine_spec.rb +42 -0
  69. data/spec/models/activity_engine/activity_spec.rb +42 -0
  70. data/spec/spec_helper.rb +35 -0
  71. data/spec/spec_patch.rb +43 -0
  72. data/spec/support/persistence_layer.rb +14 -0
  73. metadata +198 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 67279cf55dbed635e902fdd9e1360922f774bc84
4
+ data.tar.gz: 0849e330812d6b4e364dd4db17572833d472bcb3
5
+ SHA512:
6
+ metadata.gz: ad39086e8d7790407eafd2e7e26e2109fa6cd194a5b71aedc0e2fdeb189a798ea91b1b961be0582eca973b300ffa2667a90fb5a8b84aa8ea121646dccfecebc5
7
+ data.tar.gz: 6108ebb34fa9abafc41cb1d86d6e3e210574bfac5b2623ab98ed5515cf550383f8733f13bd15ad2035a0eea7d4a5ba2dcf682070f62348187948ddc3d38cb2bd
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ .bundle/
2
+ log/*.log
3
+ pkg/
4
+ spec/dummy/db/*.sqlite3
5
+ spec/dummy/log/*.log
6
+ spec/dummy/tmp/
7
+ spec/dummy/.sass-cache
8
+ Gemfile.lock
9
+ tmp/*
10
+ coverage/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,23 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Declare your gem's dependencies in activity_engine.gemspec.
4
+ # Bundler will treat runtime dependencies like base dependencies, and
5
+ # development dependencies will be added by default to the :development group.
6
+ gemspec
7
+
8
+ # jquery-rails is used by the dummy application
9
+ gem "jquery-rails"
10
+
11
+ # Declare any dependencies that are still in development here instead of in
12
+ # your gemspec. These might include edge Rails or gems from your path or
13
+ # Git. Remember to move these dependencies to your gemspec before releasing
14
+ # your gem to rubygems.org.
15
+
16
+ # To use debugger
17
+ # gem 'debugger'
18
+
19
+ group :test do
20
+ gem 'simplecov', require: false
21
+ gem "guard"
22
+ gem "guard-rspec"
23
+ end
data/Guardfile ADDED
@@ -0,0 +1,10 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec' do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/app/#{m[1]}_spec.rb" }
8
+ watch('spec/spec_helper.rb') { "spec" }
9
+ watch('spec/support/*') { "spec" }
10
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,17 @@
1
+ ##########################################################################
2
+ # activity_engine
3
+ #
4
+ # Copyright © 2013 University of Notre Dame
5
+ # Additional copyright may be held by others, as reflected in the commit history.
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # ActivityEngine
2
+
3
+ A mountable Rails engine for both recording activity and displaying activity on
4
+ a persisted object.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'activity_engine'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Then run:
17
+
18
+ $ rails g activity_engine:install
19
+
20
+ ## Register a Method
21
+
22
+ To record activity, register a class and method via a Rails generator.
23
+
24
+ $ rails g activity_engine:register <ClassName> <MethodName> <Subject>
25
+
26
+ Or by hand in a config/initializers/activity_engine_config.rb
27
+
28
+ ActivityEngine.register('<ClassName>', '<MethodName>') do |activity,context|
29
+ activity.subject = context.<subject>
30
+ activity.user = context.current_user
31
+ activity.activity_type = "an arbitrary type"
32
+ activity.message = "A particulare message?"
33
+ end
34
+
35
+ Then, whenever the ClassName#MethodName is invoke an activity will be recorded.
36
+
37
+ ## TODO
38
+
39
+ * Provide a means for retrieving an object's activities
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+
8
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
9
+ load 'rails/tasks/engine.rake'
10
+
11
+ Bundler::GemHelper.install_tasks
data/TODO.md ADDED
@@ -0,0 +1,24 @@
1
+ # Development Phases
2
+
3
+ ## Phase 1
4
+
5
+ We need basic activity reporting and collecting. At this point, we would add the registration to each of the appropriate methods.
6
+ An initial assumption is that activity logs will be stored in a different persistence engine than the objects in which there is activity.
7
+ That is to say Fedora Commons for the persisted objects, and an ActiveRecord database for the persisted objects.
8
+
9
+ ### High Level Tasks
10
+
11
+ * Allow for the creation of an Activity against a persisted object
12
+ * Allow for collecting my activity
13
+ * Allow for collecting a persisted objects activity
14
+
15
+ ### Commands
16
+
17
+ $ rails generate model JournalEntry \
18
+ journaled_object_type:string journaled_object_id:string \
19
+ requested_by_user_id:string journal_type:string \
20
+ message:text
21
+
22
+ ## Phase 2
23
+
24
+ Allow for the registration of all activity observers on an application basis.
@@ -0,0 +1,31 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+
3
+ # Maintain your gem's version:
4
+ require "activity_engine/version"
5
+
6
+ # Describe your gem and declare its dependencies:
7
+ Gem::Specification.new do |s|
8
+ s.name = "activity_engine"
9
+ s.version = ActivityEngine::VERSION
10
+ s.authors = [
11
+ "Jeremy Friesen"
12
+ ]
13
+ s.email = [
14
+ "jeremy.n.friesen@gmail.com"
15
+ ]
16
+
17
+ s.homepage = "http://github.com/ndlib/activity_engine"
18
+ s.summary = "ActivityEngine - a mountable Rails engine for activity streams"
19
+ s.description = "ActivityEngine - a mountable Rails engine for activity streams"
20
+ s.license = "APACHE2"
21
+
22
+ s.files = `git ls-files`.split("\n")
23
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
25
+ s.require_paths = ["lib"]
26
+
27
+ s.add_dependency "rails", "~> 3.2.13"
28
+
29
+ s.add_development_dependency "sqlite3"
30
+ s.add_development_dependency 'rspec-rails'
31
+ end
File without changes
@@ -0,0 +1,15 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // the compiled file.
9
+ //
10
+ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11
+ // GO AFTER THE REQUIRES BELOW.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require_tree .
@@ -0,0 +1,13 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,4 @@
1
+ module ActivityEngine
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module ActivityEngine
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,28 @@
1
+ require 'activity_engine/exceptions'
2
+ module ActivityEngine
3
+ class Activity < ActiveRecord::Base
4
+ def self.call(data)
5
+ create! do |activity|
6
+ activity.subject = data.subject
7
+ activity.user = data.current_user
8
+ activity.message = data.message
9
+ activity.activity_type = data.activity_type
10
+ end
11
+ end
12
+
13
+ belongs_to :user
14
+
15
+ def subject
16
+ subject_type.constantize.find(subject_id)
17
+ end
18
+
19
+ def subject=(object)
20
+ if object.persisted?
21
+ write_attribute(:subject_type, object.class.to_s)
22
+ write_attribute(:subject_id, object.to_param)
23
+ else
24
+ raise UnpersistedSubjectError.new(object)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>ActivityEngine</title>
5
+ <%= stylesheet_link_tag "activity_engine/application", :media => "all" %>
6
+ <%= javascript_include_tag "activity_engine/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,2 @@
1
+ ActivityEngine::Engine.routes.draw do
2
+ end
@@ -0,0 +1,13 @@
1
+ class CreateActivityEngineActivities < ActiveRecord::Migration
2
+ def change
3
+ create_table :activity_engine_activities do |t|
4
+ t.integer :user_id
5
+ t.string :subject_type, index: true, null: false
6
+ t.string :subject_id, index: true, null: false
7
+ t.string :activity_type, index: true, null: false
8
+ t.text :message
9
+ t.timestamps
10
+ end
11
+ add_index :activity_engine_activities, :user_id
12
+ end
13
+ end
@@ -0,0 +1,45 @@
1
+ require 'activity_engine/activity_data_structure'
2
+ require 'activity_engine/exceptions'
3
+ module ActivityEngine
4
+ class ActivityBuilder
5
+
6
+ attr_accessor :configuration_proc, :activity_receiver
7
+ private :activity_receiver=, :configuration_proc=
8
+
9
+ def initialize(activity_receiver, configuration_proc)
10
+ unless activity_receiver.respond_to?(:call)
11
+ raise RuntimeError, "Excpected :activity_receiver #{activity_receiver.inspect} to be callable"
12
+ end
13
+ unless configuration_proc.respond_to?(:call)
14
+ raise RuntimeError, "Excpected :configuration_proc #{configuration_proc.inspect} to be callable"
15
+ end
16
+ self.activity_receiver = activity_receiver
17
+ self.configuration_proc = configuration_proc
18
+ end
19
+
20
+ def call(context)
21
+ configuration_proc.call(self, context)
22
+ activity_receiver.call(self.to_activity_data_structure)
23
+ end
24
+
25
+ def to_activity_data_structure
26
+ ActivityDataStructure.new.tap {|ads|
27
+ ads.subject = subject
28
+ ads.current_user = current_user
29
+ ads.message = message
30
+ ads.activity_type = activity_type
31
+ }
32
+ end
33
+
34
+ def subject=(persisted_object)
35
+ if persisted_object.persisted?
36
+ @subject = persisted_object
37
+ else
38
+ raise UnpersistedSubjectError.new(persisted_object)
39
+ end
40
+ end
41
+
42
+ attr_reader :subject
43
+ attr_accessor :current_user, :message, :activity_type
44
+ end
45
+ end
@@ -0,0 +1,10 @@
1
+ module ActivityEngine
2
+ if !defined?(ActivityDataStructure)
3
+ ActivityDataStructure = Struct.new(
4
+ :subject,
5
+ :current_user,
6
+ :message,
7
+ :activity_type
8
+ )
9
+ end
10
+ end
@@ -0,0 +1,40 @@
1
+ require 'activity_engine/exceptions'
2
+ module ActivityEngine
3
+ class ContextBuilder
4
+
5
+ def initialize(class_name, method_name)
6
+ self.class_name = class_name
7
+ self.method_name = method_name
8
+ extract_context_class!
9
+ extract_method!
10
+ end
11
+
12
+ def wrap!(wrapper)
13
+ # Why the i prefix? We need the local variables to be availabe
14
+ # within the context of the module_exec.
15
+ context_class.module_exec(method_name, context_method, wrapper) { |imethod_name, icontext_method, wrapper_proc|
16
+ define_method(imethod_name) { |*args, &block|
17
+ returning_value = icontext_method.bind(self).call(*args, &block)
18
+ wrapper_proc.call(self)
19
+ returning_value
20
+ }
21
+ }
22
+ end
23
+
24
+ attr_accessor :class_name, :method_name, :context_class, :context_method
25
+ private :class_name, :method_name
26
+ private
27
+ def extract_context_class!
28
+ if class_name.respond_to?(:constantize)
29
+ @context_class = class_name.constantize
30
+ else
31
+ @context_class = class_name
32
+ end
33
+ end
34
+
35
+ def extract_method!
36
+ @context_method = context_class.instance_method(method_name)
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,17 @@
1
+ module ActivityEngine
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace ActivityEngine
4
+
5
+ config.generators do |g|
6
+ g.test_framework :rspec, :fixture => false
7
+ end
8
+
9
+ extend ActiveSupport::Autoload
10
+ eager_autoload do
11
+ autoload :ContextBuilder
12
+ autoload :ActivityBuilder
13
+ autoload :ActivityDataStructure
14
+ autoload :Activity
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ module ActivityEngine
2
+ class UnpersistedSubjectError < RuntimeError #:nodoc:
3
+ def initialize(subject)
4
+ super("#{subject.inspect} is not persisted")
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module ActivityEngine
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,14 @@
1
+ require "activity_engine/engine"
2
+ require 'activity_engine/context_builder'
3
+ require 'activity_engine/activity_builder'
4
+
5
+ module ActivityEngine
6
+ module_function
7
+
8
+ def register(class_name, method_name, activity_receiver = ActivityEngine::Activity, &config_block)
9
+ context_builder = ContextBuilder.new(class_name, method_name)
10
+ activity_builder = ActivityBuilder.new(activity_receiver, config_block)
11
+ context_builder.wrap!(activity_builder)
12
+ end
13
+
14
+ end
@@ -0,0 +1,19 @@
1
+ module ActivityEngine
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path("../templates", __FILE__)
5
+
6
+ desc "Creates a ActivityEngine initializer."
7
+
8
+ def copy_initializer
9
+ template "activity_engine_config.rb", "config/initializers/activity_engine_config.rb"
10
+ end
11
+
12
+ def run_migrations
13
+ rake('activity_engine:install:migrations')
14
+ rake('db:migrate')
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,28 @@
1
+ module ActivityEngine
2
+ module Generators
3
+ class RegisterGenerator < Rails::Generators::Base
4
+ source_root File.expand_path("../templates", __FILE__)
5
+
6
+ desc "Creates a ActivityEngine initializer."
7
+ argument :class_name, type: :string
8
+ argument :method_name, type: :string
9
+ argument :subject_method, type: :string
10
+
11
+ def copy_initializer
12
+ generate('activity_engine:install')
13
+ text = [
14
+ "ActivityEngine.register('#{class_name}', '#{method_name}') do |activity, context|",
15
+ " activity.subject = context.#{subject_method}",
16
+ " activity.user = context.current_user",
17
+ " activity.activity_type = '#{class_name}##{method_name}'",
18
+ "# activity.message = 'Specify a custom message if applicable'",
19
+ "end",
20
+ "",
21
+ ""
22
+ ].join("\n")
23
+
24
+ inject_into_file('config/initializers/activity_engine_config.rb', text, before: /\A.*ActivityEngine.register/)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,6 @@
1
+ # ActivityEngine.register('PagesController', 'show') do |activity,context|
2
+ # activity.subject = context.page
3
+ # activity.user = context.current_user
4
+ # activity.activity_type = 'pages#show'
5
+ # activity.message = "A particulare message?"
6
+ # end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :activity_engine do
3
+ # # Task goes here
4
+ # end
data/script/rails ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ ENGINE_ROOT = File.expand_path('../..', __FILE__)
5
+ ENGINE_PATH = File.expand_path('../../lib/activity_engine/engine', __FILE__)
6
+
7
+ require 'rails/all'
8
+ require 'rails/engine/commands'