velocity_check 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MjYyMTMzOGUxOTQ2MzU5MWVhYTE3NTUxNDczMmRlNDBmNDRkMzFhNw==
5
+ data.tar.gz: !binary |-
6
+ YjMwNTM0NGMwYzY0OGEwMjZlMTdlYjhlYTkzZTU5MDlhMzYyMmRlNg==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NGQ5YWYzYmRjYTdiYWJkYTdjMDcyM2E5YWM1MzQyOTVhMjQzNjMyOGU0Nzk5
10
+ YzQxNmYzZTQzZWIzMWQ4YTEwZDc2OWM1YmE5ODZjMTFkYjExMzJlN2Y3NDQ1
11
+ ZmUyNzU4NDQ3OGMzNDI3NWY5ODU4MzVlZWYzZGFjODdhYjhmNDg=
12
+ data.tar.gz: !binary |-
13
+ ZjY5MzMwMzBhMjE4NDU3ZDMwYWZhMzRlZGMxYzBkMWJkMTE3MjAyYjZhY2Q0
14
+ MGE0OGMwZTRhOTY2ZTNiNjYyNGU5YjQ1NDdhZWJjZjNlNWJiZWY1MGJjZmE3
15
+ MDA2MjhjMDRhOTUwY2U4NzM5NWQ0N2FjMmMyZTA4NGI3Mzg5NmE=
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - 2.0.0
7
+ - jruby-18mode
8
+ - jruby-19mode
9
+ - rbx-18mode
10
+ - rbx-19mode
11
+ - jruby-head
12
+ - ree
@@ -0,0 +1,4 @@
1
+ 0.0.1
2
+ =======
3
+
4
+ Initial release
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in velocity_check.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Michael Fairley
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,43 @@
1
+ # VelocityCheck
2
+
3
+ Lets you know if something is happening too often.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'velocity_check'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install velocity_check
18
+
19
+ ## Usage
20
+
21
+ ```ruby
22
+ SNEEZE_CHECK = VelocityCheck.new(:name => "sneeze", :limit => 10, :time_period => 600, :client => DALLI_CLIENT)
23
+
24
+ class Person
25
+ def initialize(name)
26
+ @name = name
27
+ end
28
+
29
+ def sneeze!
30
+ if SNEEZE_CHECK.check(@name)
31
+ puts "#{@name} has sneezed too much recently"
32
+ end
33
+ end
34
+ end
35
+ ```
36
+
37
+ ## Contributing
38
+
39
+ 1. Fork it
40
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
41
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
42
+ 4. Push to the branch (`git push origin my-new-feature`)
43
+ 5. Create new Pull Request
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,34 @@
1
+ require "velocity_check/version"
2
+
3
+ class VelocityCheck
4
+ def initialize(options)
5
+ raise ArgumentError, ":name is required" unless options[:name]
6
+ raise ArgumentError, ":name must only contain letters, numbers, and underscore" unless options[:name] =~ /\A\w+\z/
7
+ raise ArgumentError, ":limit is required" unless options[:limit]
8
+ raise ArgumentError, ":time_period is required" unless options[:time_period]
9
+ raise ArgumentError, ":client is required" unless options[:client]
10
+
11
+ known_options = [:name, :limit, :time_period, :client]
12
+ unknown_options = options.keys - known_options
13
+ raise ArgumentError, "Unknown options: #{unknown_options.map(&:to_s).sort.join(', ')}" unless unknown_options.empty?
14
+
15
+ @name = options[:name]
16
+ @client = options[:client]
17
+ @time_period = options[:time_period]
18
+ @limit = options[:limit]
19
+ end
20
+
21
+ def check(key)
22
+ full_key = "#{@name}_#{key}"
23
+
24
+ # It would nice if we could incr + touch, but touch is buggy
25
+ # in most versions of memcached (and doesn't even exist in
26
+ # debian squeeze's version).
27
+ previous = @client.get(full_key) || 0
28
+ @client.set(full_key, previous + 1, @time_period)
29
+
30
+ previous >= @limit
31
+ rescue Dalli::RingError
32
+ false
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ class VelocityCheck
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,11 @@
1
+ require 'bundler/setup'
2
+ require 'dalli'
3
+
4
+ require 'velocity_check'
5
+
6
+ RSpec.configure do |config|
7
+ config.treat_symbols_as_metadata_keys_with_true_values = true
8
+ config.run_all_when_everything_filtered = true
9
+ config.filter_run :focus
10
+ config.order = 'random'
11
+ end
@@ -0,0 +1,126 @@
1
+ require 'spec_helper'
2
+
3
+ describe VelocityCheck do
4
+ before(:all) do
5
+ Dalli.logger.level = Logger::FATAL
6
+ end
7
+
8
+ let(:client) { Dalli::Client.new("127.0.0.1:#{ENV.fetch('BOXEN_MEMCACHED_PORT', 11211)}") }
9
+ before(:each) { client.flush }
10
+
11
+ let(:options) do
12
+ {
13
+ :name => rand(10**10).to_s,
14
+ :limit => 10,
15
+ :time_period => 2,
16
+ :client => client,
17
+ }
18
+ end
19
+
20
+ describe '.new' do
21
+ it "constructs with the default options" do
22
+ VelocityCheck.new(options)
23
+ end
24
+
25
+ it "requires a name" do
26
+ expect do
27
+ VelocityCheck.new(options.merge(:name => nil))
28
+ end.to raise_error(ArgumentError, /:name is required/)
29
+ end
30
+
31
+ it "requires the name only have contain word characters" do
32
+ expect do
33
+ VelocityCheck.new(options.merge(:name => "hello!"))
34
+ end.to raise_error(ArgumentError, /name/)
35
+ expect do
36
+ VelocityCheck.new(options.merge(:name => "hello"))
37
+ end.to_not raise_error
38
+ end
39
+
40
+ it "requires a limit" do
41
+ expect do
42
+ VelocityCheck.new(options.merge(:limit => nil))
43
+ end.to raise_error(ArgumentError, ":limit is required")
44
+ end
45
+
46
+ it "requires a time_period" do
47
+ expect do
48
+ VelocityCheck.new(options.merge(:time_period => nil))
49
+ end.to raise_error(ArgumentError, ":time_period is required")
50
+ end
51
+
52
+ it "requires a client" do
53
+ expect do
54
+ VelocityCheck.new(options.merge(:client => nil))
55
+ end.to raise_error(ArgumentError, ":client is required")
56
+ end
57
+
58
+ it "does not allow extra parameters" do
59
+ expect do
60
+ VelocityCheck.new(options.merge(:extra => "hello", :more => "junk"))
61
+ end.to raise_error(ArgumentError, "Unknown options: extra, more")
62
+ end
63
+ end
64
+
65
+ describe "#check" do
66
+ subject(:checker) do
67
+ VelocityCheck.new(options)
68
+ end
69
+
70
+ it "returns false until the limit has been passed" do
71
+ 10.times do
72
+ checker.check("test").should be_false
73
+ end
74
+ end
75
+
76
+ it "returns true after the limit has been passed" do
77
+ 10.times { checker.check("test") }
78
+ checker.check("test").should be_true
79
+ end
80
+
81
+ it "returns false again after time_period has passed without a check" do
82
+ 10.times { checker.check("test") }
83
+ checker.check("test").should be_true
84
+
85
+ sleep 2
86
+
87
+ checker.check("test").should be_false
88
+ end
89
+
90
+ it "returns true as long as a check happens within every time_limit after the threshold has been bassed" do
91
+ 10.times { checker.check("test") }
92
+ 10.times do
93
+ checker.check("test").should be_true
94
+ sleep 1
95
+ end
96
+ end
97
+
98
+ it "returns false if time_period passes before the threshold check" do
99
+ 10.times { checker.check("test") }
100
+
101
+ sleep 2
102
+
103
+ checker.check("test").should be_false
104
+ end
105
+
106
+ it "isolates across the key passed in" do
107
+ 10.times { checker.check("test") }
108
+ checker.check("test2").should be_false
109
+ checker.check("test").should be_true
110
+ end
111
+
112
+ it "isolates across the name of the VelocityCheck" do
113
+ checker2 = VelocityCheck.new(options.merge(:name => "Check2"))
114
+
115
+ 10.times { checker.check("test") }
116
+ checker2.check("test").should be_false
117
+ checker.check("test").should be_true
118
+ end
119
+
120
+ it "fails open if there's an error talking to memcached" do
121
+ checker = VelocityCheck.new(options.merge(:client => Dalli::Client.new('127.0.0.1:5315')))
122
+
123
+ 100.times { checker.check("test").should be_false }
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'velocity_check/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "velocity_check"
8
+ gem.version = VelocityCheck::VERSION
9
+ gem.authors = ["Michael Fairley"]
10
+ gem.email = ["michael.fairley@getbraintree.com"]
11
+ gem.description = %q{Velocity checking}
12
+ gem.summary = %q{Lets you know if something is happening too often}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency "dalli", ">= 2"
21
+
22
+ gem.add_development_dependency "rspec", "~> 2.14"
23
+ gem.add_development_dependency "rake", "~> 10.0"
24
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: velocity_check
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Michael Fairley
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-07-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dalli
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '2.14'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '2.14'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ description: Velocity checking
56
+ email:
57
+ - michael.fairley@getbraintree.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - .rspec
64
+ - .travis.yml
65
+ - CHANGELOG.md
66
+ - Gemfile
67
+ - LICENSE.txt
68
+ - README.md
69
+ - Rakefile
70
+ - lib/velocity_check.rb
71
+ - lib/velocity_check/version.rb
72
+ - spec/spec_helper.rb
73
+ - spec/velocity_check_spec.rb
74
+ - velocity_check.gemspec
75
+ homepage: ''
76
+ licenses: []
77
+ metadata: {}
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ! '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubyforge_project:
94
+ rubygems_version: 2.0.5
95
+ signing_key:
96
+ specification_version: 4
97
+ summary: Lets you know if something is happening too often
98
+ test_files:
99
+ - spec/spec_helper.rb
100
+ - spec/velocity_check_spec.rb
101
+ has_rdoc: