action_throttler 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.
@@ -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