acts_as_recommended 0.1.0

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 ADDED
@@ -0,0 +1,11 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "rails", "3.0.9"
4
+ gem "capybara", ">= 0.4.0"
5
+ gem "sqlite3"
6
+
7
+ gem "rspec-rails", ">= 2.0.0.beta"
8
+
9
+ # To use debugger (ruby-debug for Ruby 1.8.7+, ruby-debug19 for Ruby 1.9.2+)
10
+ # gem 'ruby-debug'
11
+ # gem 'ruby-debug19'
@@ -0,0 +1,20 @@
1
+ Copyright 2011 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,88 @@
1
+ = Acts as Recommended
2
+
3
+ A simple rails 3 engine to add recommendation functionallity to your application
4
+
5
+ == Installation
6
+
7
+ Add to your *Gemfile*
8
+
9
+ gem 'acts_as_recommended'
10
+
11
+ And just run
12
+
13
+ bundle
14
+
15
+ == Usage
16
+
17
+ First thing we need is the recommendation model himself
18
+ and we have a generator that creates the model's tables
19
+
20
+ rails g acts_as_recommended:tables
21
+
22
+ After that we can add the required fields for our models with
23
+ another generator
24
+
25
+ rails g acts_as_recommended:recommendations_for Post
26
+
27
+ This will add a migration adding the required fields to add
28
+ recommendations to a certain model.
29
+
30
+ Then all we simply add this line to our desired model
31
+
32
+ acts_as_recommended
33
+
34
+ Now, we can run the migrations and we can already recommend whatever we want!
35
+
36
+ post = Post.first
37
+
38
+ bob = User.first
39
+ joe = User.last
40
+ mary = User.find(100)
41
+
42
+ post.recommend!( true, bob )
43
+ post.recommend!( 0, joe )
44
+ post.recommend!( true, mary )
45
+
46
+ # good minus bad recommendations
47
+ post.recommendations # 1
48
+
49
+ post.recommendations_count # 3
50
+
51
+ post.good_recommendations # 2
52
+ post.bad_recommendations # 1
53
+
54
+ post.good_recommendations_percent # 66.67
55
+ # pass a format optionally
56
+ post.bad_recommendations_percent( '%.1f' ) # 33.3
57
+
58
+ # check if user recommended
59
+ post.recommended_by?( bob ) # true
60
+ post.recommended_by?( mary ) # true
61
+
62
+ # get user's recommendation
63
+ post.get_recommendation_of( bob ) # true
64
+ post.get_recommendation_of( mary ) # false
65
+
66
+ Note: users can only recommend once, a second recommendation will replace the latter
67
+
68
+ == Customization
69
+
70
+ By default the recommendation must be done by a User model
71
+ you can customize that with a simple initializer like *config/initializers/recommendations.rb*
72
+
73
+ ActsAsRecommended.owner_model = :admin
74
+
75
+
76
+ == Contribution
77
+
78
+ Want to contribute? Fork, make it, ask for pull request!
79
+ Found an issue? Use the issues tracker!
80
+
81
+ == TODO
82
+
83
+ Create a simple controller to create/alter recommendations and generators for customization!
84
+
85
+ == Author
86
+
87
+ Created and mantained by Luiz Felipe Garcia Pereira aka {*Draiken*}[http://github.com/Draiken]
88
+
@@ -0,0 +1,25 @@
1
+ # encoding: UTF-8
2
+ require 'rubygems'
3
+ begin
4
+ require 'bundler/setup'
5
+ rescue LoadError
6
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
+ end
8
+
9
+ require 'rake'
10
+ require 'rake/rdoctask'
11
+
12
+ require 'rspec/core'
13
+ require 'rspec/core/rake_task'
14
+
15
+ RSpec::Core::RakeTask.new(:spec)
16
+
17
+ task :default => :spec
18
+
19
+ Rake::RDocTask.new(:rdoc) do |rdoc|
20
+ rdoc.rdoc_dir = 'rdoc'
21
+ rdoc.title = 'ActsAsRecommended'
22
+ rdoc.options << '--line-numbers' << '--inline-source'
23
+ rdoc.rdoc_files.include('README.rdoc')
24
+ rdoc.rdoc_files.include('lib/**/*.rb')
25
+ end
@@ -0,0 +1,9 @@
1
+ class Recommendation < ActiveRecord::Base
2
+
3
+ belongs_to :owner, :class_name => ActsAsRecommended.owner_class
4
+ belongs_to :recommendable, :polymorphic => true
5
+
6
+ scope :of_item, lambda { |item| where('recommendable_id = ?', item.id).where('recommendable_type = ?', item.class.base_class.name.to_s) }
7
+ scope :owned_by, lambda { |owner| where('owner_id = ?', owner.id) }
8
+
9
+ end
@@ -0,0 +1,8 @@
1
+ module ActsAsRecommended
2
+
3
+ mattr_accessor :owner_class
4
+ @@owner_class = :user
5
+
6
+ end
7
+
8
+ require 'acts_as_recommended/engine'
@@ -0,0 +1,11 @@
1
+ module ActsAsRecommended
2
+ class Engine < ::Rails::Engine
3
+ initializer :acts_as_recommended do |app|
4
+ ActiveSupport.on_load(:active_record) do
5
+ require File.join(File.dirname(__FILE__), 'model_extensions')
6
+ ::ActiveRecord::Base.send :include, ActsAsRecommended::ModelExtensions
7
+ end
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,90 @@
1
+ module ActsAsRecommended
2
+ module ModelExtensions
3
+
4
+ def self.included(base)
5
+ # :nodoc:
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+
11
+ def acts_as_recommended(*args)
12
+ return if self.included_modules.include?(ActsAsRecommended::ModelExtensions::ActsAsRecommendedMethods)
13
+ send :include, ActsAsRecommended::ModelExtensions::ActsAsRecommendedMethods
14
+ end
15
+
16
+ end
17
+
18
+ # Métodos utilizados para incrementar e decrementar os contadores
19
+ # de contribuição.
20
+ #
21
+ module ActsAsRecommendedMethods
22
+
23
+ def recommend!(recommendation, owner)
24
+ raise "Recommendation cannot be nil" if recommendation.nil?
25
+
26
+ # either a 1/0 or a true/false
27
+ recommendation = _normalize_recommendation(recommendation)
28
+
29
+ # find last recomendation of this item
30
+ # from this user or create a new one
31
+ new_recommendation = _new_or_last_recommendation_for(owner)
32
+ new_record = new_recommendation.new_record?
33
+
34
+ # return if it's the same recommendation as before
35
+ ( new_recommendation.touch and return true ) if ( not new_record and new_recommendation.recommendation == recommendation )
36
+
37
+ old_recommendation = new_recommendation.recommendation unless new_record
38
+
39
+ new_recommendation.recommendation = recommendation
40
+ new_recommendation.save
41
+
42
+ # adds the recommendation count to self if needed
43
+ self.good_recommendations += 1 if recommendation
44
+ self.bad_recommendations += 1 if not recommendation
45
+
46
+ # removes the old recomendation count if you are changing an old one
47
+ unless new_record
48
+ self.bad_recommendations -= 1 if recommendation && ( not old_recommendation )
49
+ self.good_recommendations -= 1 if !recommendation && old_recommendation
50
+ end
51
+
52
+ self.save
53
+ end
54
+
55
+ def recommendations
56
+ self.good_recommendations - self.bad_recommendations
57
+ end
58
+
59
+ def recommendations_count
60
+ self.good_recommendations + self.bad_recommendations
61
+ end
62
+
63
+ def good_recommendations_percent(format = '%.2f')
64
+ format % ((self.good_recommendations.to_f / (self.recommendations_count == 0 ? 1.to_f : self.recommendations_count.to_f)) * 100)
65
+ end
66
+
67
+ def bad_recommendations_percent(format = '%.2f')
68
+ format % ((self.bad_recommendations.to_f / (self.recommendations_count == 0 ? 1.to_f : self.recommendations_count.to_f)) * 100)
69
+ end
70
+
71
+ def recommended_by?(user)
72
+ Recommendation.of_item(self).owned_by(user).first ? true : false
73
+ end
74
+
75
+ def get_recommendation_of(user)
76
+ Recommendation.of_item(self).owned_by(user).first.recommendation
77
+ end
78
+
79
+ private
80
+
81
+ def _normalize_recommendation(recommendation)
82
+ (( recommendation.is_a?(String) || recommendation.is_a?(Fixnum) ) ? (recommendation.to_i == 1) : recommendation)
83
+ end
84
+
85
+ def _new_or_last_recommendation_for(owner)
86
+ Recommendation.of_item(self).owned_by(owner).first or Recommendation.new(:owner_id => owner.id, :recommendable_id => self.id, :recommendable_type => self.class.base_class.name)
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,26 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+
4
+ module ActsAsRecommended
5
+ module Generators
6
+ class RecommendationsForGenerator < Rails::Generators::NamedBase
7
+ include Rails::Generators::Migration
8
+
9
+ def self.source_root
10
+ File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
11
+ end
12
+
13
+ def self.next_migration_number(dirname)
14
+ if ActiveRecord::Base.timestamped_migrations
15
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
16
+ else
17
+ "%.3d" % (current_migration_number(dirname) + 1)
18
+ end
19
+ end
20
+
21
+ def manifest
22
+ migration_template "migrations/add_recommendations_to_table.rb", "db/migrate/add_recommendations_to_#{table_name}", {:assigns => {:name => name, :table_name => table_name}}
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,11 @@
1
+ class AddRecommendationsTo<%= table_name.camelize %> < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :<%= table_name %>, :good_recommendations, :integer, :default => 0
4
+ add_column :<%= table_name %>, :bad_recommendations, :integer, :default => 0
5
+ end
6
+
7
+ def self.down
8
+ remove_column :<%= table_name %>, :good_recommendations
9
+ remove_column :<%= table_name %>, :bad_recommendations
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ ./script/generate acts_as_recommended Thing
6
+
7
+ This will create:
8
+ what/will/it/create
@@ -0,0 +1,26 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+
4
+ module ActsAsRecommended
5
+ module Generators
6
+ class TablesGenerator < Rails::Generators::Base
7
+ include Rails::Generators::Migration
8
+
9
+ def self.source_root
10
+ File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
11
+ end
12
+
13
+ def self.next_migration_number(dirname)
14
+ if ActiveRecord::Base.timestamped_migrations
15
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
16
+ else
17
+ "%.3d" % (current_migration_number(dirname) + 1)
18
+ end
19
+ end
20
+
21
+ def manifest
22
+ migration_template "migrations/create_recommendations.rb", "db/migrate/create_recommendations"
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ class CreateRecommendations < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :recommendations do |t|
4
+ t.references :recommendable, :polymorphic => true, :null => false
5
+ t.references :owner, :null => false
6
+ t.boolean :recommendation, :null => false
7
+
8
+ t.timestamps
9
+ end
10
+
11
+ add_index :recommendations, [:recommendable_type, :recommendable_id], :name => 'idx_recommendations'
12
+ add_index :recommendations, [:recommendable_type, :recommendable_id, :owner_id], :unique => true, :name => 'idx_recommendations_user'
13
+ add_index :recommendations, [:recommendable_type, :recommendable_id, :recommendation], :name => 'idx_recommendations_type'
14
+ end
15
+
16
+ def self.down
17
+ drop_table :recommendations
18
+ end
19
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: acts_as_recommended
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Luiz Felipe Garcia Pereira
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-06-17 00:00:00 -03:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rails
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 3
32
+ - 0
33
+ version: "3.0"
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ description: Insert ActsAsRecommended description.
37
+ email:
38
+ - luiz.felipe.gp@gmail.com
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files: []
44
+
45
+ files:
46
+ - app/models/recommendation.rb
47
+ - lib/acts_as_recommended/engine.rb
48
+ - lib/acts_as_recommended/model_extensions.rb
49
+ - lib/acts_as_recommended.rb
50
+ - lib/generators/acts_as_recommended/recommendations_for/recommendations_for_generator.rb
51
+ - lib/generators/acts_as_recommended/recommendations_for/templates/migrations/add_recommendations_to_table.rb
52
+ - lib/generators/acts_as_recommended/tables/tables_generator.rb
53
+ - lib/generators/acts_as_recommended/tables/templates/migrations/create_recommendations.rb
54
+ - lib/generators/acts_as_recommended/tables/USAGE
55
+ - MIT-LICENSE
56
+ - Rakefile
57
+ - Gemfile
58
+ - README.rdoc
59
+ has_rdoc: true
60
+ homepage:
61
+ licenses: []
62
+
63
+ post_install_message:
64
+ rdoc_options: []
65
+
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ hash: 3
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ hash: 3
83
+ segments:
84
+ - 0
85
+ version: "0"
86
+ requirements: []
87
+
88
+ rubyforge_project:
89
+ rubygems_version: 1.6.2
90
+ signing_key:
91
+ specification_version: 3
92
+ summary: Insert ActsAsRecommended summary.
93
+ test_files: []
94
+