newcomb 1.0.0 → 1.1.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.
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: 51b5f6f749151b7198392e67fbc778794f984e74f59ec5c5eb1ba5915756f6a3
4
+ data.tar.gz: aecd46607250e7732dfc04e9934c1b4e6daa9c2913493f75e89de5c8c7322588
5
5
  SHA512:
6
- metadata.gz: 57922988b4fc725ff86fc6d591e6398c86fdfbf378ef7aa627031834d0b979c7b5ef7dbfb68303513849eb671f417867bda55d8b17e6ac056746426b3646c81f
7
- data.tar.gz: e5b2a92ddc77101a22f7899c8f1a70433cd5b16d4e991c2940da091bd510f51f2643414823737775d6733cf5512bb72ff41d25339f62d919ecc66687714988ea
6
+ metadata.gz: 336095c63051df0e59d21006c4cc9293002e38fa9b47fe25ee27c68c1bc09b83a746c0f1ab81d07b21753860b6aad2c5847257b7c135bd4c8be9cc7fca929ace
7
+ data.tar.gz: 1e316c09fad0f3d71cedc27a5879bfccff3d197be1421879e84369c56d3fef5df6319298a486e0f369091bf26c4ef30d74b027fb2fe5e08d62561efdc46b0f59
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
@@ -1,12 +1,16 @@
1
- # Newcomb
1
+ <h1>
2
+ <picture>
3
+ <source media="(prefers-color-scheme: light)" srcset="https://github.com/user-attachments/assets/15369987-a098-48d2-a9ca-301127a77e86">
4
+ <source media="(prefers-color-scheme: dark)" srcset="https://github.com/user-attachments/assets/1be2dd40-8060-49ef-810c-576b4a1cefa7">
5
+ <img alt="Newcomb" src="https://github.com/user-attachments/assets/15369987-a098-48d2-a9ca-301127a77e86" style="height:2em">
6
+ </picture>
7
+ </h1>
2
8
 
3
9
  Generate random numbers that adhere to [Benford's Law](http://en.wikipedia.org/wiki/Benford's_law)
4
10
 
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)
11
+ [![Made by laserlemon](https://img.shields.io/badge/laser-lemon-fc0?style=flat-square)](https://github.com/laserlemon)
12
+ [![Gem version](https://img.shields.io/gem/v/newcomb?style=flat-square)](https://rubygems.org/gems/newcomb)
13
+ [![Build status](https://img.shields.io/github/actions/workflow/status/laserlemon/newcomb/test.yml?style=flat-square)](https://github.com/laserlemon/newcomb/actions/workflows/test.yml)
10
14
 
11
15
  ## Usage
12
16
 
@@ -23,6 +27,26 @@ To fetch a random positive integer, provide the upper (exclusive) limit:
23
27
  Newcomb.random_number(100) # => 16
24
28
  ```
25
29
 
30
+ To fetch a random positive float, provide the upper (exclusive) limit as a float:
31
+
32
+ ```ruby
33
+ Newcomb.random_number(100.0) # => 21.895884449446473
34
+ ```
35
+
36
+ To fetch a random integer within a range, provide a range with integer endpoints:
37
+
38
+ ```ruby
39
+ Newcomb.random_number(100..1000) # => 141
40
+ ```
41
+
42
+ To fetch a random float within a range, provide a range with float (or mixed) endpoints:
43
+
44
+ ```ruby
45
+ Newcomb.random_number(100.0..1000.0) # => 203.90587157406662
46
+ Newcomb.random_number(100..1000.0) # => 424.9768102233391
47
+ Newcomb.random_number(100.0..1000) # => 628.7978615329862
48
+ ```
49
+
26
50
  Over a sufficiently large sample size, the distribution of Newcomb's random
27
51
  numbers will demonstrate Benford's Law.
28
52
 
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Newcomb
4
+ VERSION = Gem::Version.new("1.1.1")
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,65 +1,64 @@
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.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Richert
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2014-07-15 00:00:00.000000000 Z
10
+ date: 2025-06-30 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: bundler
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
- - - "~>"
16
+ - - ">="
18
17
  - !ruby/object:Gem::Version
19
- version: '1.6'
18
+ version: '2'
20
19
  type: :development
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
- - - "~>"
23
+ - - ">="
25
24
  - !ruby/object:Gem::Version
26
- version: '1.6'
25
+ version: '2'
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: rake
29
28
  requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
- - - "~>"
30
+ - - ">="
32
31
  - !ruby/object:Gem::Version
33
- version: '10.3'
32
+ version: '13'
34
33
  type: :development
35
34
  prerelease: false
36
35
  version_requirements: !ruby/object:Gem::Requirement
37
36
  requirements:
38
- - - "~>"
37
+ - - ">="
39
38
  - !ruby/object:Gem::Version
40
- version: '10.3'
39
+ version: '13'
41
40
  description: Generate random numbers that adhere to Benford's Law
42
- email: steve.richert@gmail.com
41
+ email: steve.richert@hey.com
43
42
  executables: []
44
43
  extensions: []
45
- extra_rdoc_files: []
44
+ extra_rdoc_files:
45
+ - README.md
46
46
  files:
47
- - ".gitignore"
48
- - ".rspec"
49
- - ".travis.yml"
50
- - Gemfile
51
47
  - LICENSE.txt
52
48
  - README.md
53
- - Rakefile
54
49
  - lib/newcomb.rb
50
+ - lib/newcomb/version.rb
55
51
  - newcomb.gemspec
56
- - spec/newcomb_spec.rb
57
- - spec/spec_helper.rb
58
52
  homepage: https://github.com/laserlemon/newcomb
59
53
  licenses:
60
54
  - MIT
61
- metadata: {}
62
- post_install_message:
55
+ metadata:
56
+ allowed_push_host: https://rubygems.org
57
+ bug_tracker_uri: https://github.com/laserlemon/newcomb/issues
58
+ funding_uri: https://github.com/sponsors/laserlemon
59
+ homepage_uri: https://github.com/laserlemon/newcomb
60
+ rubygems_mfa_required: 'true'
61
+ source_code_uri: https://github.com/laserlemon/newcomb
63
62
  rdoc_options: []
64
63
  require_paths:
65
64
  - lib
@@ -67,18 +66,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
67
66
  requirements:
68
67
  - - ">="
69
68
  - !ruby/object:Gem::Version
70
- version: '0'
69
+ version: 3.0.0
71
70
  required_rubygems_version: !ruby/object:Gem::Requirement
72
71
  requirements:
73
72
  - - ">="
74
73
  - !ruby/object:Gem::Version
75
74
  version: '0'
76
75
  requirements: []
77
- rubyforge_project:
78
- rubygems_version: 2.2.2
79
- signing_key:
76
+ rubygems_version: 3.6.2
80
77
  specification_version: 4
81
78
  summary: Generate natural random numbers
82
- test_files:
83
- - spec/newcomb_spec.rb
84
- - spec/spec_helper.rb
79
+ 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"