newcomb 1.0.0 → 1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: b718f0e37121533e31fe9c789e912422c12406f2
4
- data.tar.gz: 49c5cb53702a3f6f8db7f2cb34c0fea50d732337
2
+ SHA256:
3
+ metadata.gz: 7cd2e97fc6d20d043706a8d5957d993910cbc910d4694654f3a7a5eceec790a3
4
+ data.tar.gz: 1b177fe3f68b65f4511b275719fc8db3955824c9f9126366d79d9c9753960ac2
5
5
  SHA512:
6
- metadata.gz: 57922988b4fc725ff86fc6d591e6398c86fdfbf378ef7aa627031834d0b979c7b5ef7dbfb68303513849eb671f417867bda55d8b17e6ac056746426b3646c81f
7
- data.tar.gz: e5b2a92ddc77101a22f7899c8f1a70433cd5b16d4e991c2940da091bd510f51f2643414823737775d6733cf5512bb72ff41d25339f62d919ecc66687714988ea
6
+ metadata.gz: 872d2e86d6520395cf1941d12b132c3dd8e9f4e166cb15ee35056317e2d0e30e6fe373b51aebc3c5bf5af2687da4ddfd80330e0b5cfb653d6e66ca612edb6592
7
+ data.tar.gz: 33042d3d6bf19205385e3139fcf5b4bbf3d83dba230f005c2d125126f70fd65b3e0ca5e3fab18b850d707aed7ed4dd2ae3b26d7034d8ea3ea52d99a9101ae4bd
data/LICENSE.txt CHANGED
@@ -1,22 +1,21 @@
1
- Copyright (c) 2014 Steve Richert
1
+ The MIT License (MIT)
2
2
 
3
- MIT License
3
+ Copyright (c) 2014 Steve Richert
4
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:
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
12
11
 
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
15
14
 
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.
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md CHANGED
@@ -2,11 +2,8 @@
2
2
 
3
3
  Generate random numbers that adhere to [Benford's Law](http://en.wikipedia.org/wiki/Benford's_law)
4
4
 
5
- [![Gem Version](https://img.shields.io/gem/v/newcomb.svg?style=flat)](http://rubygems.org/gems/newcomb)
6
- [![Build Status](https://img.shields.io/travis/laserlemon/newcomb/master.svg?style=flat)](https://travis-ci.org/laserlemon/newcomb)
7
- [![Code Climate](https://img.shields.io/codeclimate/github/laserlemon/newcomb.svg?style=flat)](https://codeclimate.com/github/laserlemon/newcomb)
8
- [![Code Coverage](http://img.shields.io/codeclimate/coverage/github/laserlemon/newcomb.svg?style=flat)](https://codeclimate.com/github/laserlemon/newcomb)
9
- [![Dependency Status](https://img.shields.io/gemnasium/laserlemon/newcomb.svg?style=flat)](https://gemnasium.com/laserlemon/newcomb)
5
+ [![Gem Version](https://img.shields.io/gem/v/newcomb)](http://rubygems.org/gems/newcomb)
6
+ [![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/laserlemon/newcomb/rake.yml)](https://github.com/laserlemon/newcomb/actions/workflows/rake.yml)
10
7
 
11
8
  ## Usage
12
9
 
@@ -23,6 +20,26 @@ To fetch a random positive integer, provide the upper (exclusive) limit:
23
20
  Newcomb.random_number(100) # => 16
24
21
  ```
25
22
 
23
+ To fetch a random positive float, provide the upper (exclusive) limit as a float:
24
+
25
+ ```ruby
26
+ Newcomb.random_number(100.0) # => 21.895884449446473
27
+ ```
28
+
29
+ To fetch a random integer within a range, provide a range with integer endpoints:
30
+
31
+ ```ruby
32
+ Newcomb.random_number(100..1000) # => 141
33
+ ```
34
+
35
+ To fetch a random float within a range, provide a range with float (or mixed) endpoints:
36
+
37
+ ```ruby
38
+ Newcomb.random_number(100.0..1000.0) # => 203.90587157406662
39
+ Newcomb.random_number(100..1000.0) # => 424.9768102233391
40
+ Newcomb.random_number(100.0..1000) # => 628.7978615329862
41
+ ```
42
+
26
43
  Over a sufficiently large sample size, the distribution of Newcomb's random
27
44
  numbers will demonstrate Benford's Law.
28
45
 
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Newcomb
4
+ VERSION = Gem::Version.new("1.1.0")
5
+ end
data/lib/newcomb.rb CHANGED
@@ -1,11 +1,68 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "securerandom"
2
4
 
5
+ # The Newcomb module is the interface to its random_number function which is
6
+ # designed to behave identically to SecureRandom.random_number except for the
7
+ # distribution of its return values. Like SecureRandom, the
8
+ # Newcomb.random_number function can be given a single argument in one of the
9
+ # following forms:
10
+ #
11
+ # Integer - The random number returned will be an Integer between 0 and the
12
+ # given maximum, exclusive.
13
+ # Float - The random number returned will be a Float between 0.0 and the
14
+ # given maximum, exclusive.
15
+ # Range - The random number returned will be either an Integer or Float,
16
+ # depending on the endpoints of the range, and within the range.
3
17
  module Newcomb
4
- def self.random_number(n = 0)
5
- if n > 0
6
- (random_number * n).floor
18
+ # The 3-element "constraints" array represents the minimum allowed value,
19
+ # the maximum allowed value, and whether the final value should be rounded
20
+ # down to the nearest integer.
21
+ DEFAULT_CONTRAINTS = [0, 1, false].freeze
22
+
23
+ def self.random_number(arg = nil)
24
+ random_factor = ((10 ** SecureRandom.random_number) - 1) / 9
25
+ min, max, round = generate_constraints(arg)
26
+ float_value = (random_factor * (max - min)) + min
27
+ round ? float_value.floor : float_value
28
+ end
29
+
30
+ def self.generate_constraints(arg)
31
+ case arg
32
+ when nil then DEFAULT_CONTRAINTS
33
+ when Range then generate_constraints_from_range(arg)
34
+ when Integer, Float then generate_constraints_from_max(arg)
35
+ else invalid_argument!(arg)
36
+ end
37
+ end
38
+
39
+ def self.generate_constraints_from_range(range)
40
+ first = range.first
41
+ last = range.last
42
+
43
+ # The given range must have integer/float endpoints.
44
+ unless (first.is_a?(Integer) || first.is_a?(Float)) && (last.is_a?(Integer) || last.is_a?(Float))
45
+ invalid_argument!(range)
46
+ end
47
+
48
+ if first < last
49
+ # We only round the final value down if both endpoints of the range
50
+ # are integers, mirroring the behavior of SecureRandom.random_number.
51
+ [first, last, first.is_a?(Integer) && last.is_a?(Integer)]
52
+ else
53
+ DEFAULT_CONTRAINTS
54
+ end
55
+ end
56
+
57
+ def self.generate_constraints_from_max(max)
58
+ if max.positive?
59
+ [0, max, max.is_a?(Integer)]
7
60
  else
8
- (10 ** SecureRandom.random_number - 1) / 9
61
+ DEFAULT_CONTRAINTS
9
62
  end
10
63
  end
64
+
65
+ def self.invalid_argument!(arg)
66
+ raise ArgumentError, "invalid argument - #{arg}"
67
+ end
11
68
  end
data/newcomb.gemspec CHANGED
@@ -1,19 +1,37 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
- Gem::Specification.new do |spec|
4
- spec.name = "newcomb"
5
- spec.version = "1.0.0"
3
+ require_relative "lib/newcomb/version"
6
4
 
7
- spec.author = "Steve Richert"
8
- spec.email = "steve.richert@gmail.com"
9
- spec.summary = "Generate natural random numbers"
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "newcomb"
7
+ spec.summary = "Generate natural random numbers"
10
8
  spec.description = "Generate random numbers that adhere to Benford's Law"
11
- spec.homepage = "https://github.com/laserlemon/newcomb"
12
- spec.license = "MIT"
9
+ spec.version = Newcomb::VERSION
10
+
11
+ spec.author = "Steve Richert"
12
+ spec.email = "steve.richert@hey.com"
13
+ spec.license = "MIT"
14
+ spec.homepage = "https://github.com/laserlemon/newcomb"
15
+
16
+ spec.metadata = {
17
+ "allowed_push_host" => "https://rubygems.org",
18
+ "bug_tracker_uri" => "https://github.com/laserlemon/newcomb/issues",
19
+ "funding_uri" => "https://github.com/sponsors/laserlemon",
20
+ "homepage_uri" => "https://github.com/laserlemon/newcomb",
21
+ "rubygems_mfa_required" => "true",
22
+ "source_code_uri" => "https://github.com/laserlemon/newcomb",
23
+ }
24
+
25
+ spec.required_ruby_version = ">= 3.0.0"
26
+ spec.add_development_dependency "bundler", ">= 2"
27
+ spec.add_development_dependency "rake", ">= 13"
13
28
 
14
- spec.files = `git ls-files -z`.split("\x0")
15
- spec.test_files = spec.files.grep(/^spec/)
29
+ spec.files = [
30
+ "lib/newcomb.rb",
31
+ "lib/newcomb/version.rb",
32
+ "LICENSE.txt",
33
+ "newcomb.gemspec",
34
+ ]
16
35
 
17
- spec.add_development_dependency "bundler", "~> 1.6"
18
- spec.add_development_dependency "rake", "~> 10.3"
36
+ spec.extra_rdoc_files = ["README.md"]
19
37
  end
metadata CHANGED
@@ -1,64 +1,65 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: newcomb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Richert
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-15 00:00:00.000000000 Z
11
+ date: 2024-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.6'
19
+ version: '2'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.6'
26
+ version: '2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '10.3'
33
+ version: '13'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '10.3'
40
+ version: '13'
41
41
  description: Generate random numbers that adhere to Benford's Law
42
- email: steve.richert@gmail.com
42
+ email: steve.richert@hey.com
43
43
  executables: []
44
44
  extensions: []
45
- extra_rdoc_files: []
45
+ extra_rdoc_files:
46
+ - README.md
46
47
  files:
47
- - ".gitignore"
48
- - ".rspec"
49
- - ".travis.yml"
50
- - Gemfile
51
48
  - LICENSE.txt
52
49
  - README.md
53
- - Rakefile
54
50
  - lib/newcomb.rb
51
+ - lib/newcomb/version.rb
55
52
  - newcomb.gemspec
56
- - spec/newcomb_spec.rb
57
- - spec/spec_helper.rb
58
53
  homepage: https://github.com/laserlemon/newcomb
59
54
  licenses:
60
55
  - MIT
61
- metadata: {}
56
+ metadata:
57
+ allowed_push_host: https://rubygems.org
58
+ bug_tracker_uri: https://github.com/laserlemon/newcomb/issues
59
+ funding_uri: https://github.com/sponsors/laserlemon
60
+ homepage_uri: https://github.com/laserlemon/newcomb
61
+ rubygems_mfa_required: 'true'
62
+ source_code_uri: https://github.com/laserlemon/newcomb
62
63
  post_install_message:
63
64
  rdoc_options: []
64
65
  require_paths:
@@ -67,18 +68,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
67
68
  requirements:
68
69
  - - ">="
69
70
  - !ruby/object:Gem::Version
70
- version: '0'
71
+ version: 3.0.0
71
72
  required_rubygems_version: !ruby/object:Gem::Requirement
72
73
  requirements:
73
74
  - - ">="
74
75
  - !ruby/object:Gem::Version
75
76
  version: '0'
76
77
  requirements: []
77
- rubyforge_project:
78
- rubygems_version: 2.2.2
78
+ rubygems_version: 3.5.7
79
79
  signing_key:
80
80
  specification_version: 4
81
81
  summary: Generate natural random numbers
82
- test_files:
83
- - spec/newcomb_spec.rb
84
- - spec/spec_helper.rb
82
+ test_files: []
data/.gitignore DELETED
@@ -1,22 +0,0 @@
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
18
- *.bundle
19
- *.so
20
- *.o
21
- *.a
22
- mkmf.log
data/.rspec DELETED
@@ -1,4 +0,0 @@
1
- --color
2
- --format documentation
3
- --order random
4
- --require spec_helper
data/.travis.yml DELETED
@@ -1,19 +0,0 @@
1
- branches:
2
- only:
3
- - master
4
- env:
5
- global:
6
- secure: | # CODECLIMATE_REPO_TOKEN
7
- XnaAxp9pN9OR+jSyLUXQwKkMVcUfNy+7muWXKLQRi/zIh2ObGBCEXTww/8mP
8
- hwv4Rf8a4n7+gpQhmv6MEx3xwdArkxLChs1EX79XGNN9/g/DBPtfoiKB3FLd
9
- UUJTuPurAlOklt/s+XvJTV5h50ThpvutSqkSenO5me8v/ODO6hw=
10
- language: ruby
11
- matrix:
12
- allow_failures:
13
- - rvm: ruby-head
14
- rvm:
15
- - 1.9.3
16
- - "2.0"
17
- - "2.1"
18
- - ruby-head
19
- script: bundle exec rspec
data/Gemfile DELETED
@@ -1,8 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gemspec
4
-
5
- group :test do
6
- gem "codeclimate-test-reporter", require: false
7
- gem "rspec", "~> 3.0"
8
- end
data/Rakefile DELETED
@@ -1,6 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
-
4
- RSpec::Core::RakeTask.new(:spec)
5
-
6
- task default: :spec
data/spec/newcomb_spec.rb DELETED
@@ -1,68 +0,0 @@
1
- describe Newcomb do
2
- describe ".random_number" do
3
- let(:sample_size) { 1_000_000 }
4
-
5
- def assert_benford(&block)
6
- distribution = build_distribution(&block)
7
-
8
- expect(distribution.keys).to match_array([1, 2, 3, 4, 5, 6, 7, 8, 9])
9
-
10
- distribution.sort.each do |i, count|
11
- expect(distribution[i]).to be_within(tolerance(i)).of(expected_count(i))
12
- end
13
- end
14
-
15
- def build_distribution(&block)
16
- sample_size.times.with_object({}) do |_, memo|
17
- digit = block.call
18
- memo[digit] ||= 0
19
- memo[digit] += 1
20
- end
21
- end
22
-
23
- def build_sample(&block)
24
- sample_size.times.map(&block)
25
- end
26
-
27
- # TODO: Update to assert adherence to within one standard deviation
28
- def tolerance(digit)
29
- (expected_count(digit) * 0.01).round
30
- end
31
-
32
- def expected_count(digit)
33
- (((Math.log(digit + 1) - Math.log(digit)) / Math.log(10)) * sample_size).round
34
- end
35
-
36
- context "when given no arguments" do
37
- it "falls between zero (inclusive) and one (exclusive)" do
38
- sample = build_sample { Newcomb.random_number }
39
-
40
- expect(sample.map(&:class).uniq).to eq([Float])
41
- expect(sample.map(&:floor).uniq).to eq([0])
42
- end
43
-
44
- it "is distributed according to Benford's law" do
45
- assert_benford do
46
- (Newcomb.random_number * 9).floor + 1
47
- end
48
- end
49
- end
50
-
51
- context "when given an argument" do
52
- it "falls between zero (inclusive) and the given number (exclusive)" do
53
- sample = sample_size.times.map { Newcomb.random_number(13) }
54
-
55
- expect(sample.map(&:class).uniq).to eq([Fixnum])
56
- floors = sample.map(&:floor)
57
- expect(floors.min).to be >= 0
58
- expect(floors.max).to be < 13
59
- end
60
-
61
- it "is distributed according to Benford's law" do
62
- assert_benford do
63
- Newcomb.random_number(9) + 1
64
- end
65
- end
66
- end
67
- end
68
- end
data/spec/spec_helper.rb DELETED
@@ -1,6 +0,0 @@
1
- if ENV["CODECLIMATE_REPO_TOKEN"]
2
- require "codeclimate-test-reporter"
3
- CodeClimate::TestReporter.start
4
- end
5
-
6
- require "newcomb"