action_throttler 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,95 @@
1
+ # Action Throttler
2
+
3
+ There is also a PHP version (for [Kohana](http://kohanaframework.org/)), see here: http://github.com/fredwu/kthrottler
4
+
5
+ ## Introduction
6
+
7
+ Action Throttler is an easy to use Rails plugin to quickly throttle application actions based on configurable duration and limit.
8
+
9
+ Brought to you by [Envato](http://envato.com) and [Wuit](http://wuit.com).
10
+
11
+ ## Features
12
+
13
+ * Easy to use, easy to configure
14
+ * Lightweight
15
+ * Supports both Rails 2 and 3
16
+
17
+ ## Limitations
18
+
19
+ * Supports ActiveRecord only
20
+ * Uses Rake instead of Rails Generator for file generation (for compatibility purpose)
21
+
22
+ ## Usage
23
+
24
+ ### Download and install the plugin
25
+
26
+ #### Rails 2
27
+
28
+ script/plugin install http://fredwu@github.com/fredwu/action_throttler.git
29
+
30
+ #### Rails 3
31
+
32
+ rails plugin install http://fredwu@github.com/fredwu/action_throttler.git
33
+
34
+ ### Set up the plugin
35
+
36
+ To generate the migration file and migrate the database:
37
+
38
+ rake action_throttler:migrate
39
+ rake db:migrate
40
+
41
+ Or alternatively:
42
+
43
+ rake action_throttler:auto_migrate
44
+
45
+ ### Configure the actions
46
+
47
+ The configuration file is located at `PATH_TO_YOUR_APP/config/initializers/action_throttler.rb`.
48
+
49
+ The configuration block looks like this:
50
+
51
+ ActionThrottler::Actions.add :mail do |action|
52
+ action.duration = 1.hour
53
+ action.limit = 10
54
+ end
55
+
56
+ You can add as many configuration blocks as you like, just make sure you label them properly (i.e. like `:mail` in the example).
57
+
58
+ In the example, we are setting the `:mail` action to perform at most <em>10</em> times within <em>1</em> hour duration.
59
+
60
+ ### Register the actions in your app
61
+
62
+ Now we will need to register the actions so they are recorded in the database.
63
+
64
+ To simply run an action, in your app (presumably somewhere in the controller), do this:
65
+
66
+ ActionThrottler::Actions.run(:mail)
67
+
68
+ `ActionThrottler::Actions.run` will return `true` or `false` depending on whether or not the action is being throttled.
69
+
70
+ `ActionThrottler::Actions.run` has an alias `ActionThrottler::Actions.can_run` and a negative alias `ActionThrottler::Actions.cannot_run`.
71
+
72
+ Typically, we would want to produce feedback to the user when an action is throttled, you can do so by:
73
+
74
+ if ActionThrottler::Actions.cannot_run(:mail)
75
+ # tell the user that this action is not performed
76
+ end
77
+
78
+ `ActionThrottler::Actions.run` also takes an optional `reference` parameter:
79
+
80
+ ActionThrottler::Actions.run(:mail, @current_user)
81
+
82
+ The reference parameter is very useful because we can track and throttle the action based on a reference, such as a user. The parameter accepts a `String`, an `Integer` or an `ActiveRecord` object.
83
+
84
+ Note that `ActionThrottler::Actions.run` and its aliases will perform the action when possible. If you only want to check to see if an action can be performed, you can do this:
85
+
86
+ ActionThrottler::Actions.can_be_run?(:mail, @current_user)
87
+
88
+ `ActionThrottler::Actions.can_be_run?` returns `true` or `false` without performing the action, and it also has a negative alias, `ActionThrottler::Actions.cannot_be_run?`.
89
+
90
+ ## Author
91
+
92
+ Copyright (c) 2010 Fred Wu (<http://fredwu.me>), released under the MIT license
93
+
94
+ * Envato - <http://envato.com>
95
+ * Wuit - <http://wuit.com>
@@ -0,0 +1,28 @@
1
+ require 'rake'
2
+ require 'spec/rake/spectask'
3
+
4
+ desc 'Default: run specs.'
5
+ task :default => :spec
6
+
7
+ desc 'Run the specs'
8
+ Spec::Rake::SpecTask.new(:spec) do |t|
9
+ t.spec_opts = ['--colour --format progress --loadby mtime --reverse']
10
+ t.spec_files = FileList['spec/**/*_spec.rb']
11
+ end
12
+
13
+ begin
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |s|
16
+ s.name = "action_throttler"
17
+ s.version = "0.1.0"
18
+ s.summary = "Action Throttler is an easy to use Rails plugin to quickly throttle application actions based on configurable duration and limit."
19
+ s.description = "Action Throttler is an easy to use Rails plugin to quickly throttle application actions based on configurable duration and limit."
20
+ s.email = "ifredwu@gmail.com"
21
+ s.homepage = "http://github.com/fredwu/action_throttler"
22
+ s.authors = ["Fred Wu"]
23
+ s.add_dependency("activerecord")
24
+ end
25
+ Jeweler::GemcutterTasks.new
26
+ rescue LoadError
27
+ puts "Jeweler not available. Install it with: gem install jeweler"
28
+ end
@@ -0,0 +1,58 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{action_throttler}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Fred Wu"]
12
+ s.date = %q{2010-08-09}
13
+ s.description = %q{Action Throttler is an easy to use Rails plugin to quickly throttle application actions based on configurable duration and limit.}
14
+ s.email = %q{ifredwu@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ "README.md",
20
+ "Rakefile",
21
+ "action_throttler.gemspec",
22
+ "init.rb",
23
+ "install.rb",
24
+ "lib/action_throttler/actions.rb",
25
+ "lib/action_throttler/config.rb",
26
+ "lib/action_throttler/model.rb",
27
+ "lib/tasks/action_throttler.rake",
28
+ "lib/tasks/initializer/action_throttler.rb",
29
+ "lib/tasks/migration/create_action_throttler_logs.rb",
30
+ "lib/tasks/rake_helper.rb",
31
+ "spec/action_throttler_spec.rb",
32
+ "spec/spec_helper.rb",
33
+ "uninstall.rb"
34
+ ]
35
+ s.homepage = %q{http://github.com/fredwu/action_throttler}
36
+ s.rdoc_options = ["--charset=UTF-8"]
37
+ s.require_paths = ["lib"]
38
+ s.rubygems_version = %q{1.3.7}
39
+ s.summary = %q{Action Throttler is an easy to use Rails plugin to quickly throttle application actions based on configurable duration and limit.}
40
+ s.test_files = [
41
+ "spec/action_throttler_spec.rb",
42
+ "spec/spec_helper.rb"
43
+ ]
44
+
45
+ if s.respond_to? :specification_version then
46
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
47
+ s.specification_version = 3
48
+
49
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
50
+ s.add_runtime_dependency(%q<activerecord>, [">= 0"])
51
+ else
52
+ s.add_dependency(%q<activerecord>, [">= 0"])
53
+ end
54
+ else
55
+ s.add_dependency(%q<activerecord>, [">= 0"])
56
+ end
57
+ end
58
+
data/init.rb ADDED
@@ -0,0 +1,3 @@
1
+ require File.dirname(__FILE__) + "/lib/action_throttler/actions"
2
+ require File.dirname(__FILE__) + "/lib/action_throttler/config"
3
+ require File.dirname(__FILE__) + "/lib/action_throttler/model"
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1,75 @@
1
+ module ActionThrottler
2
+ class Actions
3
+ class << self
4
+ # Adds an action to the stack
5
+ #
6
+ # @param [Symbol] action the name of the action, must be unique
7
+ # @param [Block] block the configuration block
8
+ def add(action = nil, &block)
9
+ @actions ||= {}
10
+
11
+ raise "A name to the ActionThrottler action is required!" if action.nil?
12
+
13
+ config = ActionThrottler::Config.new
14
+ block.call(config)
15
+
16
+ @actions[action] = config.to_hash
17
+ end
18
+
19
+ # Checks the database to see if an action can be run
20
+ #
21
+ # @param [Symbol] action the name of the action to be run
22
+ # @param [Mixed] ref (optional) the reference object
23
+ # @return [Boolean] returns true or false depending on the outcome
24
+ def can_be_run?(action, ref = "")
25
+ ::ActionThrottlerLog.all(:conditions => [
26
+ "scope = ? AND reference = ? AND created_at >= ?",
27
+ action.to_s,
28
+ normalise_ref(ref),
29
+ @actions[action][:duration].ago
30
+ ]).size < @actions[action][:limit] ? true : false
31
+ end
32
+
33
+ # @see self::can_be_run?
34
+ def cannot_be_run?(action, ref = "")
35
+ not can_be_run?(action, ref)
36
+ end
37
+
38
+ # Runs an action and registers it in the database
39
+ #
40
+ # @param [Symbol] action the name of the action to be run
41
+ # @param [Mixed] ref (optional) the reference object
42
+ # @return [Boolean] returns true or false depending on the outcome
43
+ def run(action, ref = "")
44
+ if can_be_run?(action, ref)
45
+ ::ActionThrottlerLog.create({
46
+ :scope => action.to_s,
47
+ :reference => normalise_ref(ref)
48
+ })
49
+ else
50
+ false
51
+ end
52
+ end
53
+
54
+ # @see self::run
55
+ def can_run(action, ref = "")
56
+ run(action, ref)
57
+ end
58
+
59
+ # @see self::run
60
+ def cannot_run(action, ref = "")
61
+ ! run(action, ref)
62
+ end
63
+
64
+ private
65
+
66
+ # Normalises the ref parameter so it can accept more than one type
67
+ #
68
+ # @param [Mixed] ref the ref parameter
69
+ # @return [String] ref id
70
+ def normalise_ref(ref)
71
+ (ref.is_a?(Integer) || ref.is_a?(String)) ? ref.to_s : ref.id.to_s
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,18 @@
1
+ module ActionThrottler
2
+ class Config
3
+ def initialize
4
+ @config ||= {}
5
+ end
6
+
7
+ def to_hash
8
+ @config
9
+ end
10
+
11
+ def method_missing(key, value)
12
+ # converts `key=()` methods to `key()`
13
+ key = key.to_s.sub(/=$/, "").to_sym
14
+
15
+ @config[key] = value
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,2 @@
1
+ class ActionThrottlerLog < ActiveRecord::Base
2
+ end
@@ -0,0 +1,28 @@
1
+ require File.dirname(__FILE__) + "/rake_helper"
2
+
3
+ module ActionThrottler
4
+ class Tasks
5
+ include ActionThrottler::Rake
6
+
7
+ def self.run!
8
+ namespace :action_throttler do
9
+ desc "Generates the Action Throttler initializer file"
10
+ task :init => :environment do
11
+ copy_initializer_file "The Action Throttler initializer file has been generated."
12
+ end
13
+
14
+ desc "Generates the Action Throttler database migration file"
15
+ task :migrate => :init do
16
+ copy_migration_file "The Action Throttler migration file has been generated."
17
+ end
18
+
19
+ desc "Generates the Action Throttler database migration file and migrates the database"
20
+ task :auto_migrate => :migrate do
21
+ ::Rake::Task["db:migrate"].invoke
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ ActionThrottler::Tasks.run!
@@ -0,0 +1,4 @@
1
+ # ActionThrottler::Actions.add :mail do |action|
2
+ # action.duration = 1.hour
3
+ # action.limit = 10
4
+ # end
@@ -0,0 +1,17 @@
1
+ class CreateActionThrottlerLogs < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :action_throttler_logs, :force => true do |t|
4
+ t.string :scope
5
+ t.string :reference
6
+ t.timestamps
7
+ end
8
+
9
+ add_index :action_throttler_logs, :scope
10
+ add_index :action_throttler_logs, :reference
11
+ add_index :action_throttler_logs, [:scope, :reference]
12
+ end
13
+
14
+ def self.down
15
+ drop_table :action_throttler_logs
16
+ end
17
+ end
@@ -0,0 +1,55 @@
1
+ require "rails/railties/lib/rails_generator/base"
2
+ require "rails/railties/lib/rails_generator/commands"
3
+
4
+ module ActionThrottler
5
+ module Rake
6
+ def self.included(base)
7
+ base.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ # Copies the migration file to `db/migrate`
12
+ #
13
+ # @param [String] message optional output message
14
+ def copy_migration_file(message = "")
15
+ orig_dir = "#{File.dirname(__FILE__)}/migration/"
16
+ orig_file = Dir.entries(orig_dir).last
17
+ orig_path = orig_dir + orig_file
18
+
19
+ prefix = Rails::Generator::Commands::Base.new(nil).send(:next_migration_string)
20
+ dest_path = "db/migrate/#{prefix}_#{orig_file}"
21
+
22
+ copy_file(orig_path, dest_path, message)
23
+ end
24
+
25
+ # Copies the initializer file to `config/initializers`
26
+ #
27
+ # @param [String] message optional output message
28
+ def copy_initializer_file(message = "")
29
+ orig_dir = "#{File.dirname(__FILE__)}/initializer/"
30
+ orig_file = Dir.entries(orig_dir).last
31
+ orig_path = orig_dir + orig_file
32
+
33
+ dest_path = "config/initializers/#{orig_file}"
34
+
35
+ copy_file(orig_path, dest_path, message)
36
+ end
37
+
38
+ # Copies a file
39
+ #
40
+ # @param [String] orig_path original file path, absolute
41
+ # @param [String] dest_path destination file path, relative to `Rails.root`
42
+ # @param [String] message optional output message
43
+ def copy_file(orig_path, dest_path, message = "")
44
+ dest_path = "#{Rails.root}/#{dest_path}"
45
+
46
+ if File.exists?(dest_path)
47
+ puts "'#{dest_path}' already exists, therefore it is skipped."
48
+ else
49
+ FileUtils.cp(orig_path, dest_path)
50
+ puts message unless message.nil?
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
@@ -0,0 +1,10 @@
1
+ begin
2
+ require File.dirname(__FILE__) + '/../../../../spec/spec_helper'
3
+ rescue LoadError
4
+ puts "You need to install rspec in your base app"
5
+ exit
6
+ end
7
+
8
+ plugin_spec_dir = File.dirname(__FILE__)
9
+ ActiveRecord::Base.logger = Logger.new(plugin_spec_dir + "/debug.log")
10
+
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: action_throttler
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Fred Wu
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-08-09 00:00:00 +10:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: activerecord
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ description: Action Throttler is an easy to use Rails plugin to quickly throttle application actions based on configurable duration and limit.
36
+ email: ifredwu@gmail.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - README.md
43
+ files:
44
+ - README.md
45
+ - Rakefile
46
+ - action_throttler.gemspec
47
+ - init.rb
48
+ - install.rb
49
+ - lib/action_throttler/actions.rb
50
+ - lib/action_throttler/config.rb
51
+ - lib/action_throttler/model.rb
52
+ - lib/tasks/action_throttler.rake
53
+ - lib/tasks/initializer/action_throttler.rb
54
+ - lib/tasks/migration/create_action_throttler_logs.rb
55
+ - lib/tasks/rake_helper.rb
56
+ - spec/action_throttler_spec.rb
57
+ - spec/spec_helper.rb
58
+ - uninstall.rb
59
+ has_rdoc: true
60
+ homepage: http://github.com/fredwu/action_throttler
61
+ licenses: []
62
+
63
+ post_install_message:
64
+ rdoc_options:
65
+ - --charset=UTF-8
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.3.7
90
+ signing_key:
91
+ specification_version: 3
92
+ summary: Action Throttler is an easy to use Rails plugin to quickly throttle application actions based on configurable duration and limit.
93
+ test_files:
94
+ - spec/action_throttler_spec.rb
95
+ - spec/spec_helper.rb