velocity_check 0.0.1

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,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: