suimin 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,3 @@
1
+ --tty
2
+ --colour
3
+ --format <%= ENV["CI"] ? 'progress' : 'documentation'%>
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "https://rubygems.org"
2
+
3
+ group :test do
4
+ gem "rspec", "~> 2.11"
5
+ unless ENV["CI"]
6
+ gem "guard-rspec"
7
+ gem "rb-fsevent"
8
+ end
9
+ end
10
+
11
+ gem "rake"
12
+
13
+ gemspec
@@ -0,0 +1,9 @@
1
+ # vim:set filetype=ruby:
2
+ guard(
3
+ "rspec",
4
+ all_after_pass: false,
5
+ cli: "--fail-fast --tty --format documentation --colour") do
6
+
7
+ watch(%r{^spec/.+_spec\.rb$})
8
+ watch(%r{^lib/(.+)\.rb$}) { |match| "spec/#{match[1]}_spec.rb" }
9
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Koichi Hirano
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,29 @@
1
+ # Suimin
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'suimin'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install suimin
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,38 @@
1
+ require "suimin/version"
2
+
3
+ module Suimin
4
+
5
+ autoload :Sleeper, 'suimin/sleeper'
6
+
7
+ class TypeError < Exception; end
8
+ class SleeperNotFound < StandardError; end
9
+
10
+ # a hash whose key is the sleeper's name, and the value is the sleeper
11
+ @@sleepers = {}
12
+
13
+ class << self
14
+ def sleepers
15
+ @@sleepers
16
+ end
17
+
18
+ def add_sleeper(_sleeper)
19
+ raise TypeError.new("sleeper should be Suimin::Sleeper instance") unless _sleeper.is_a?(Suimin::Sleeper)
20
+
21
+ sleepers[_sleeper.name] = _sleeper
22
+ end
23
+
24
+ def let_sleeper_sleep(_sleeper_name)
25
+ if (sleeper = sleepers[_sleeper_name])
26
+ sleeper.sleep
27
+ else
28
+ raise SleeperNotFound.new("Sleeper #{_sleeper_name} cannot be found")
29
+ end
30
+ end
31
+
32
+ end
33
+
34
+ def self.config
35
+ yield self
36
+ end
37
+
38
+ end
@@ -0,0 +1,48 @@
1
+ require 'securerandom'
2
+
3
+ class Suimin::Sleeper
4
+
5
+ attr_reader :name, :distribution
6
+
7
+ # _config[:name]:i The name of the sleeper instance.
8
+ # _config[:distribution]: An array of arrays whose element is [_probablility_, _sleep_duration_in_second_]
9
+ # For example [0.5, 1] means the probablity of sleeping for 1 second is 0.5
10
+ # If sum of the probability isn't 1.0, the probablities are normalized automatically.
11
+ # For example, [[1.0, 1], [1.0, 3]] => [[0.5, 1], [0.5, 3]]
12
+ def initialize(_config)
13
+ @distribution = normalize_distribution(_config[:distribution]).sort{|a,b| a[0] <=> b[0]}
14
+ @name = _config[:name]
15
+ end
16
+
17
+ # converts the distribution to cdf
18
+ def rule
19
+ @rule || @distribution.inject([]){|result, elm| result << [(result.empty? ? 0.0 : result.last[0]) + elm[0], elm[1]]}\
20
+ .tap{|array| array.last[0] = 1.0 } # make sure the last element's cdf is 1.0
21
+ end
22
+
23
+ def sleep
24
+ Kernel.sleep sleep_duration
25
+ end
26
+
27
+ def sleep_duration
28
+ return 0 if rule.empty?
29
+
30
+ _rand = SecureRandom.random_number
31
+ rule.find{|elm| elm[0] >= _rand}[1]
32
+ end
33
+
34
+ def expected_sleep_duration_value
35
+ distribution.inject(0.0) {|res, elm| res += elm[0] * elm[1] }
36
+ end
37
+
38
+ private
39
+ def normalize_distribution(_distribution)
40
+ if _distribution.nil? || _distribution.empty?
41
+ raise InvalidRuleException.new("distribution should be an array of [probability, sleep_time_in_sec]")
42
+ end
43
+ _sum = _distribution.inject(0.0){|result, elm| result += elm[0] }
44
+ return _distribution.collect{|elm| [elm[0]/_sum, elm[1]]}
45
+ end
46
+
47
+ class InvalidRuleException < StandardError; end
48
+ end
@@ -0,0 +1,3 @@
1
+ module Suimin
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,9 @@
1
+ require 'suimin'
2
+
3
+ RSpec.configure do |config|
4
+ config.treat_symbols_as_metadata_keys_with_true_values = true
5
+ config.run_all_when_everything_filtered = true
6
+ config.filter_run :focus
7
+
8
+ config.order = 'random'
9
+ end
@@ -0,0 +1,103 @@
1
+ require 'spec_helper'
2
+ require 'benchmark'
3
+
4
+ describe Suimin::Sleeper do
5
+ describe "initialization" do
6
+ let(:suimin) { Suimin::Sleeper.new(name: "ichiro", distribution: [[0.2, 1], [0.8, 2]]) }
7
+ subject { suimin }
8
+ its(:name) { should == "ichiro" }
9
+ its(:distribution) { should == [[0.2, 1], [0.8, 2]]}
10
+ end
11
+
12
+ describe "#distribution" do
13
+
14
+ describe "normalize distribution of the distribution" do
15
+ subject { suimin.distribution }
16
+
17
+ context "the given distribution has [0.2, 1], [0.8, 2]" do
18
+ let(:suimin) { Suimin::Sleeper.new(name: "ichiro", distribution: [[0.2, 1], [0.8, 2]]) }
19
+ subject { suimin.distribution }
20
+ it { should == [[0.2, 1], [0.8, 2]] }
21
+ end
22
+
23
+ context "the given distribution has [0.2, 1], [0.2, 2]" do
24
+ let(:suimin) { Suimin::Sleeper.new(name: "ichiro", distribution: [[0.2, 1], [0.2, 2]]) }
25
+ subject { suimin.distribution }
26
+ it { should == [[0.5, 1], [0.5, 2]] }
27
+ end
28
+
29
+ end
30
+
31
+ describe "sort the distribution elements by probability" do
32
+ subject { suimin.distribution }
33
+
34
+ context "the given distribution has [0.8, 1], [0.2, 2]" do
35
+ let(:suimin) { Suimin::Sleeper.new(name: "ichiro", distribution: [[0.8, 1], [0.2, 2]]) }
36
+ subject { suimin.distribution }
37
+ it { should == [[0.2, 2], [0.8, 1]] }
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+
44
+ describe "#rule" do #rule is a list of possible sleep interval in the form of cumulative distribution function
45
+ subject { suimin.rule }
46
+
47
+ context "the given distribution has [0.8, 1], [0.2, 2]" do
48
+ let(:suimin) { Suimin::Sleeper.new(name: "ichiro", distribution: [[0.8, 1], [0.2, 2]]) }
49
+ subject { suimin.rule }
50
+ it { should == [[0.2, 2], [1.0, 1]] }
51
+ end
52
+
53
+ end
54
+
55
+ describe "#sleep_duration" do
56
+ subject { suimin.sleep_duration }
57
+
58
+ context "given [0.8, 1], [0.2, 2] and SecureRandom::random_number returns 0.0" do
59
+ before { SecureRandom.stub(random_number: 0.0) }
60
+ let(:suimin) { Suimin::Sleeper.new(name: "ichiro", distribution: [[0.8, 1], [0.2, 2]]) }
61
+ it { should == 2 }
62
+ end
63
+
64
+ context "given [0.8, 1], [0.2, 2] and SecureRandom::random_number returns 0.2" do
65
+ before { SecureRandom.stub(random_number: 0.2) }
66
+ let(:suimin) { Suimin::Sleeper.new(name: "ichiro", distribution: [[0.8, 1], [0.2, 2]]) }
67
+ it { should == 2 }
68
+ end
69
+
70
+ context "given [0.8, 1], [0.2, 2] and SecureRandom::random_number returns 0.21" do
71
+ before { SecureRandom.stub(random_number: 0.21) }
72
+ let(:suimin) { Suimin::Sleeper.new(name: "ichiro", distribution: [[0.8, 1], [0.2, 2]]) }
73
+ it { should == 1 }
74
+ end
75
+
76
+ context "given [0.8, 1], [0.2, 2] and SecureRandom::random_number returns 1.0" do
77
+ before { SecureRandom.stub(random_number: 1.0) }
78
+ let(:suimin) { Suimin::Sleeper.new(name: "ichiro", distribution: [[0.8, 1], [0.2, 2]]) }
79
+ it { should == 1 }
80
+ end
81
+
82
+ end
83
+
84
+ describe "#expected_sleep_duration_value" do
85
+ context "given [0.8, 1], [0.2, 2]" do
86
+ subject { suimin.expected_sleep_duration_value }
87
+ let(:suimin) { Suimin::Sleeper.new(name: "ichiro", distribution: [[0.8, 1], [0.2, 2]]) }
88
+ it { should be_within(0.0000001).of(1.2) }
89
+ end
90
+ end
91
+
92
+ describe "#sleep" do
93
+
94
+ context "the given distribution has [0.2, 0.1], [0.8, 0.05]" do
95
+ let(:suimin) { Suimin::Sleeper.new(name: "ichiro", distribution: [[0.2, 0.1], [0.8, 0.05]]) }
96
+
97
+ specify "calling 100 times would take approximately 100 * 0.2 * 0.1 + 100 * 0.8 * 0.05" do
98
+ Benchmark.realtime { 1.upto(100) { suimin.sleep } }.should be_within(1.0).of(6.0)
99
+ end
100
+ end
101
+
102
+ end
103
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe Suimin do
4
+
5
+ describe "::config" do
6
+ let(:sleeper) { Suimin::Sleeper.new(name: "napper", distribution: [[0.2, 0.1], [0.8, 0.2]]) }
7
+ before do
8
+ Suimin.config do |config|
9
+ config.add_sleeper sleeper
10
+ end
11
+ end
12
+
13
+ it "should have set sleepers" do
14
+ Suimin.sleepers[sleeper.name].should == sleeper
15
+ end
16
+ end
17
+
18
+ describe "::let_sleeper_sleep" do
19
+ let(:quick_napper) { Suimin::Sleeper.new(name: "quick_napper", distribution: [[0.2, 0.2], [0.8, 0.1]]) }
20
+ let(:snoozer) { Suimin::Sleeper.new(name: "snoozer", distribution: [[0.2, 2], [0.8, 1]]) }
21
+ let(:sleepers) { [quick_napper, snoozer] }
22
+ before do
23
+ Suimin.config do |s|
24
+ s.add_sleeper quick_napper
25
+ s.add_sleeper snoozer
26
+ end
27
+ end
28
+
29
+ specify "Suimin::let_sleeper_sleep with quick_napper should call quick_napper.sleep" do
30
+ quick_napper.should_receive(:sleep).and_return(true)
31
+ snoozer.should_not_receive(:sleep)
32
+ Suimin.let_sleeper_sleep("quick_napper")
33
+ end
34
+
35
+ specify "Suimin::let_sleeper_sleep with non-existent sleeper should blow up" do
36
+ lambda { Suimin.let_sleeper_sleep("not_registered_napper") }.should raise_exception(Suimin::SleeperNotFound)
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'suimin/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "suimin"
8
+ gem.version = Suimin::VERSION
9
+ gem.authors = ["Koichi Hirano"]
10
+ gem.email = ["internalist@gmail.com"]
11
+ gem.description = %q{A gem which provides a method that sleeps in the way you want}
12
+ gem.summary = %q{When you need to have a sleeping behavior following a certain statistical distribution, this is the gem for you.}
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_development_dependency 'rspec', '~> 2.10'
21
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: suimin
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Koichi Hirano
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-04-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '2.10'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '2.10'
30
+ description: A gem which provides a method that sleeps in the way you want
31
+ email:
32
+ - internalist@gmail.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - .rspec
39
+ - Gemfile
40
+ - Guardfile
41
+ - LICENSE.txt
42
+ - README.md
43
+ - Rakefile
44
+ - lib/suimin.rb
45
+ - lib/suimin/sleeper.rb
46
+ - lib/suimin/version.rb
47
+ - spec/spec_helper.rb
48
+ - spec/suimin/sleeper_spec.rb
49
+ - spec/suimin_spec.rb
50
+ - suimin.gemspec
51
+ homepage: ''
52
+ licenses: []
53
+ post_install_message:
54
+ rdoc_options: []
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ segments:
64
+ - 0
65
+ hash: -3559506569192083543
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ segments:
73
+ - 0
74
+ hash: -3559506569192083543
75
+ requirements: []
76
+ rubyforge_project:
77
+ rubygems_version: 1.8.23
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: When you need to have a sleeping behavior following a certain statistical
81
+ distribution, this is the gem for you.
82
+ test_files:
83
+ - spec/spec_helper.rb
84
+ - spec/suimin/sleeper_spec.rb
85
+ - spec/suimin_spec.rb