croupier 1.6.0 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +2 -2
  3. data/Rakefile +7 -0
  4. data/lib/croupier/distribution.rb +115 -36
  5. data/lib/croupier/distribution_generator.rb +57 -0
  6. data/lib/croupier/distribution_generators/enumerator_block_generator.rb +23 -0
  7. data/lib/croupier/distribution_generators/enumerator_generator.rb +21 -0
  8. data/lib/croupier/distribution_generators/inverse_cdf_generator.rb +21 -0
  9. data/lib/croupier/distribution_generators/minimum_sample_generator.rb +24 -0
  10. data/lib/croupier/distribution_generators.rb +18 -0
  11. data/lib/croupier/distributions/bernoulli.rb +18 -25
  12. data/lib/croupier/distributions/binomial.rb +30 -29
  13. data/lib/croupier/distributions/cauchy.rb +22 -19
  14. data/lib/croupier/distributions/credit_card.rb +39 -29
  15. data/lib/croupier/distributions/degenerate.rb +16 -19
  16. data/lib/croupier/distributions/exponential.rb +18 -19
  17. data/lib/croupier/distributions/gamma.rb +66 -37
  18. data/lib/croupier/distributions/geometric.rb +19 -20
  19. data/lib/croupier/distributions/nbinomial.rb +22 -33
  20. data/lib/croupier/distributions/normal.rb +30 -34
  21. data/lib/croupier/distributions/poisson.rb +26 -25
  22. data/lib/croupier/distributions/triangular.rb +39 -25
  23. data/lib/croupier/distributions/uniform.rb +43 -19
  24. data/lib/croupier/distributions.rb +3 -4
  25. data/lib/croupier/version.rb +1 -1
  26. data/lib/croupier.rb +43 -6
  27. data/test/minitest/distribution_class/test_class_methods.rb +142 -0
  28. data/test/{test_distribution_class.rb → minitest/distribution_class/test_instance_methods.rb} +26 -28
  29. data/test/minitest/distribution_generator_class/test_class_methods.rb +24 -0
  30. data/test/minitest/distribution_generator_class/test_instance_methods.rb +35 -0
  31. data/test/minitest/distribution_generators/test_enumerator_block_generator.rb +31 -0
  32. data/test/minitest/distribution_generators/test_enumerator_generator.rb +33 -0
  33. data/test/minitest/distribution_generators/test_inverse_cdf_generator.rb +36 -0
  34. data/test/minitest/distribution_generators/test_minimum_sample_generator.rb +33 -0
  35. data/test/minitest/distributions/test_bernoulli_distribution.rb +13 -0
  36. data/test/minitest/distributions/test_binomial_distribution.rb +18 -0
  37. data/test/minitest/distributions/test_cauchy_distribution.rb +18 -0
  38. data/test/{distributions/minitest/test_credit_card.rb → minitest/distributions/test_credit_card_distribution.rb} +5 -0
  39. data/test/{distributions/minitest → minitest/distributions}/test_degenerate_distribution.rb +2 -2
  40. data/test/minitest/distributions/test_exponential_distribution.rb +13 -0
  41. data/test/minitest/distributions/test_gamma_distribution.rb +23 -0
  42. data/test/minitest/distributions/test_geometric_distribution.rb +13 -0
  43. data/test/minitest/distributions/test_normal_distribution.rb +17 -0
  44. data/test/minitest/distributions/test_poisson_distribution.rb +13 -0
  45. data/test/minitest/distributions/test_triangular_distribution.rb +26 -0
  46. data/test/minitest/distributions/test_uniform_distribution.rb +54 -0
  47. data/test/{test_croupier_module.rb → minitest/test_croupier_module.rb} +0 -0
  48. data/test/minitest/test_distribution_generators_module.rb +37 -0
  49. data/test/{test_distributions_module.rb → minitest/test_distributions_module.rb} +0 -0
  50. data/test/rtests.R +1 -0
  51. metadata +62 -44
  52. data/test/distributions/R_tests/test_bernoulli.R +0 -17
  53. data/test/distributions/R_tests/test_binomial.R +0 -17
  54. data/test/distributions/R_tests/test_cauchy.R +0 -28
  55. data/test/distributions/R_tests/test_exponential.R +0 -28
  56. data/test/distributions/R_tests/test_gamma.R +0 -27
  57. data/test/distributions/R_tests/test_geometric.R +0 -23
  58. data/test/distributions/R_tests/test_nbinomial.R +0 -17
  59. data/test/distributions/R_tests/test_normal.R +0 -52
  60. data/test/distributions/R_tests/test_poisson.R +0 -17
  61. data/test/distributions/R_tests/test_triangular.R +0 -28
  62. data/test/distributions/R_tests/test_uniform.R +0 -30
  63. data/test/testsuite.R +0 -37
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bf6d755404722c636a61587f2381ca5ff96ff62b
4
+ data.tar.gz: 2229632adcaab36de7a98fd4d1d6bca922485a6d
5
+ SHA512:
6
+ metadata.gz: c03a5dcb2b26a88b3d6ccfb0bc205b72576ed9d4e802a10823ffca194ee291b8bbbe650870ba6a522e1c473fdee4216e64a1e6e7b78118366fa9f7182bd0a12f
7
+ data.tar.gz: 463e5689dc2fe99f689706925acfa1951689369617b9c4b58598f025e9e222661f79fd13f74976a3e3fff4c51b25053b767633703ca2c627e4639c00528fbab4
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  Croupier generates random samples of numbers with specific probability distributions.
4
4
 
5
5
  [![Gem Version](https://badge.fury.io/rb/croupier.png)](http://badge.fury.io/rb/croupier)
6
- [![Build Status](https://secure.travis-ci.org/xuanxu/croupier.png?branch=master)](http://travis-ci.org/xuanxu/croupier)
6
+ [![Build Status](https://secure.travis-ci.org/croupiers/croupier-rb.png?branch=2.0)](http://travis-ci.org/croupiers/croupier-rb)
7
7
 
8
8
  ## Install
9
9
 
@@ -84,7 +84,7 @@ To get a list of all available distributions/methods in Distributions module cal
84
84
 
85
85
  Croupier::Distributions.list
86
86
 
87
- Since 1.6.0, distributions have a ```to_enum``` method that return an (infinity) enumerator, so you
87
+ Distributions have a ```to_enum``` method that return an (infinity) enumerator, so you
88
88
  can use any Enumerable method on it:
89
89
 
90
90
  dist = Croupier::Distributions.exponential(:lambda => 17).to_enum
data/Rakefile CHANGED
@@ -7,3 +7,10 @@ Rake::TestTask.new do |t|
7
7
  end
8
8
  task :default => :test
9
9
 
10
+ namespace :test do
11
+ task :distributions do
12
+ puts `./generate_test_data.sh`
13
+ puts `cd test && Rscript rtests.R`
14
+ end
15
+ end
16
+
@@ -6,13 +6,107 @@ module Croupier
6
6
  #
7
7
  class Distribution
8
8
  attr_accessor :parameters
9
- attr_reader :name, :description
9
+ attr_accessor :generator
10
+
11
+ class << self
12
+ # Sets the name property of the distribution.
13
+ # if given
14
+ #
15
+ # @param distribution_name [String,nil] the name of the distribution
16
+ # @return [String] current distribution name
17
+ def distribution_name distribution_name=nil
18
+ @distribution_name = distribution_name if distribution_name
19
+ @distribution_name
20
+ end
21
+
22
+ # Sets the description property of the distribution
23
+ # if given
24
+ #
25
+ # @param description [String,nil] description for the distribution
26
+ # @return [String] current description
27
+ def distribution_description description=nil
28
+ @distribution_description = description if description
29
+ @distribution_description
30
+ end
31
+
32
+ # Sets the generator class for this distribution, if given
33
+ #
34
+ # @param generator_class [Class] class for the generator for this distribution
35
+ # @return [Class] current generator class
36
+ def generator_class generator_class=nil
37
+ @generator_class = generator_class if generator_class
38
+ @generator_class
39
+ end
40
+
41
+ # Sets the generator block for this distribution, if given
42
+ #
43
+ # @param block [Proc] block for the generator
44
+ # @return [Proc] current generator block
45
+ def generator_block &block
46
+ @generator_block = block if block_given?
47
+ @generator_block
48
+ end
49
+
50
+ # Defines a hash with banner and all available CLI options.
51
+ # It is a hash with two keys:
52
+ # :banner => A string used as banner in the command line help
53
+ # :options => An array of arrays each one representing a CLI option
54
+ # with the following format:[:option, 'description', {hash of option params}]
55
+ # Example:
56
+ # {:banner => "This distribution generates only number 33",
57
+ # :options => [
58
+ # [:mean, 'The mean of the distribution', {:default => 33}],
59
+ # [:median, 'Median of the distribution',{:default => 33.0, :type => :float}]
60
+ # ]
61
+ # }
62
+ # @param options [Hash] new cli options
63
+ # return [Hash] current cli options
64
+ def cli_options options=nil
65
+ @cli_options = options if options
66
+ @cli_options || {}
67
+ end
68
+
69
+ # Sets the cli_name if given
70
+ #
71
+ # @param cli_name [String] new cli name
72
+ # @return [String] current cli name
73
+ def cli_name cli_name=nil
74
+ @cli_name = cli_name if cli_name
75
+ @cli_name
76
+ end
77
+
78
+ def default_parameters
79
+ Hash[(cli_options[:options]||{}).map do |name, desc, hash|
80
+ [name,hash[:default]]
81
+ end]
82
+ end
83
+
84
+ def method_missing(method, *args, &block) # :nodoc:
85
+ return super unless self.respond_to?(method)
86
+ generator = ::Croupier::DistributionGenerators.all.find{|d| d.method_name == method.to_s}
87
+ self.generator_class generator
88
+ self.generator_block &block
89
+ end
90
+
91
+ def respond_to?(method, include_private = false) # :nodoc:
92
+ ::Croupier::DistributionGenerators.list.include?(method.to_s) || super(method, include_private)
93
+ end
94
+ end
10
95
 
11
96
  # Initializes Distribution object and adds received options to the distribution parameters.
12
97
  def initialize(options={})
13
- @name = nil
14
- @description = nil
15
98
  configure(options)
99
+ create_generator
100
+ end
101
+
102
+ # Alias for `self.class.distribution_name`
103
+ # @return [String] distribution name
104
+ def name
105
+ self.class.distribution_name
106
+ end
107
+
108
+ def description
109
+ self.class.distribution_description
16
110
  end
17
111
 
18
112
  # Merge the hash of options into the default distribution parameters
@@ -22,25 +116,17 @@ module Croupier
22
116
 
23
117
  # Default hash of distribution parameters
24
118
  def default_parameters
25
- {}
119
+ self.class.default_parameters
26
120
  end
27
121
 
28
122
  # Main method to generate n random numbers using the current probability distribution
29
123
  def generate_sample(n=1)
30
- if self.respond_to? :inv_cdf
31
- (1..n).map{ inv_cdf(rand) }
32
- else
33
- (1..n).map{ generate_number }
34
- end
124
+ self.to_enum.take(n).to_a
35
125
  end
36
126
 
37
127
  # Generates one random number using the current probability distribution
38
128
  def generate_number
39
- if self.respond_to? :inv_cdf
40
- inv_cdf(rand)
41
- else
42
- generate_sample(1).first
43
- end
129
+ self.to_enum.next
44
130
  end
45
131
 
46
132
  # convenience method for lazy programmers
@@ -48,32 +134,25 @@ module Croupier
48
134
  @parameters
49
135
  end
50
136
 
51
- # Defines a hash with banner and all available CLI options.
52
- # It is a hash with two keys:
53
- # :banner => A string used as banner in the command line help
54
- # :options => An array of arrays each one representing a CLI option
55
- # with the following format:[:option, 'description', {hash of option params}]
56
- # Example:
57
- # {:banner => "This distribution generates only number 33",
58
- # :options => [
59
- # [:mean, 'The mean of the distribution', {:default => 33}],
60
- # [:median, 'Median of the distribution',{:default => 33.0, :type => :float}]
61
- # ]
62
- # }
63
- def self.cli_options
64
- {:banner => nil, :options=>[]}
65
- end
137
+ # Make Croupier::Distribution an Enumerable
138
+ include Enumerable
66
139
 
67
- # Defines the name of this Distribution to be used from the CLI.
68
- def self.cli_name
69
- ''
140
+ def each &block
141
+ if block_given?
142
+ self.to_enum.each &block
143
+ else
144
+ self.to_enum.each
145
+ end
70
146
  end
71
147
 
72
148
  def to_enum
73
- Enumerator.new do |y|
74
- loop do
75
- y << generate_number
76
- end
149
+ @enum ||= @generator.to_enum.lazy
150
+ end
151
+
152
+ protected
153
+ def create_generator
154
+ if self.class.generator_class && self.class.generator_block
155
+ @generator = self.class.generator_class.new self, &self.class.generator_block
77
156
  end
78
157
  end
79
158
  end
@@ -0,0 +1,57 @@
1
+ module Croupier
2
+
3
+ class DistributionGenerator
4
+
5
+ class << self
6
+
7
+ # Gets and optionally sets the method name for this generator
8
+ #
9
+ # @param new_method_name [String] new method name
10
+ # @return [String] current method name
11
+ def method_name new_method_name=nil
12
+ @method_name = new_method_name if new_method_name
13
+ @method_name
14
+ end
15
+ end
16
+
17
+ attr_reader :distribution
18
+ attr_reader :block
19
+
20
+ def initialize distribution, &block
21
+ @distribution = distribution
22
+ @block = block
23
+ end
24
+
25
+
26
+ # Accessor to distribution parameters
27
+ #
28
+ # @return [Hash<String,Object>] distribution parameters
29
+ def params
30
+ self.distribution.params
31
+ end
32
+
33
+ def croupier
34
+ ::Croupier::Distributions
35
+ end
36
+
37
+ # @abstract Given some parameters, returns the minimum sample
38
+ # it can generate. Some generators generate more
39
+ # than one number each iteration.
40
+ #
41
+ # @return [Array<Numeric>] sample
42
+ def generate_minimum_sample
43
+
44
+ end
45
+
46
+ def to_enum
47
+ Enumerator.new do |y|
48
+ loop do
49
+ sample = self.generate_minimum_sample
50
+ sample.each do |s|
51
+ y << s
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,23 @@
1
+ module Croupier
2
+
3
+ module DistributionGenerators
4
+
5
+ # Call `enumerator_block` with a block
6
+ # that will be called as the parameter for
7
+ # Enumerator.new
8
+ class EnumeratorBlockGenerator < ::Croupier::DistributionGenerator
9
+
10
+ method_name "enumerator_block"
11
+
12
+ def initilize distribution, &block
13
+ super distribution, &block
14
+ end
15
+
16
+ def to_enum
17
+ Enumerator.new do |y|
18
+ self.distribution.instance_exec(y,&self.block)
19
+ end.lazy
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ module Croupier
2
+
3
+ module DistributionGenerators
4
+
5
+ # Call `enumerator` with a block
6
+ # that returns an enumerator.
7
+ # First block argument is the Croupier::Distributions module
8
+ class EnumeratorGenerator < ::Croupier::DistributionGenerator
9
+
10
+ method_name "enumerator"
11
+
12
+ def initilize distribution, &block
13
+ super distribution, &block
14
+ end
15
+
16
+ def to_enum
17
+ self.distribution.instance_exec(::Croupier::Distributions, &self.block).lazy
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module Croupier
2
+
3
+ module DistributionGenerators
4
+
5
+ class InverseCDFGenerator < ::Croupier::DistributionGenerator
6
+
7
+ method_name "inv_cdf"
8
+
9
+ def initilize distribution, &block
10
+ super distribution, &block
11
+ end
12
+
13
+ def to_enum
14
+ # Fix when final api is availble
15
+ croupier.uniform.to_enum.lazy.map do |n|
16
+ distribution.instance_exec(n, &self.block)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ module Croupier
2
+
3
+ module DistributionGenerators
4
+
5
+ class MinimumSampleGenerator < ::Croupier::DistributionGenerator
6
+
7
+ method_name "minimum_sample"
8
+
9
+ def initilize distribution, &block
10
+ super distribution, &block
11
+ end
12
+
13
+ def to_enum
14
+ Enumerator.new do |y|
15
+ loop do
16
+ distribution.instance_exec(&self.block).each do |a|
17
+ y << a
18
+ end
19
+ end
20
+ end.lazy
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,18 @@
1
+ module Croupier
2
+ module DistributionGenerators
3
+ class << self
4
+ # An array containing all available Distribution classes
5
+ def all
6
+ ::Croupier::DistributionGenerators.constants(false).each_with_object([]){|distrib,list|
7
+ d = ::Croupier::DistributionGenerators.const_get(distrib)
8
+ list << d if (d.is_a?(Class) && d.superclass == Croupier::DistributionGenerator)
9
+ }.uniq.compact
10
+ end
11
+
12
+ # list of all available distribution names (and methods on Distributions module)
13
+ def list
14
+ self.all.map(&:method_name).sort
15
+ end
16
+ end
17
+ end
18
+ end
@@ -8,37 +8,30 @@ module Croupier
8
8
  # Equivalent to a Binomial(1,p)
9
9
  class Bernoulli < ::Croupier::Distribution
10
10
 
11
- def initialize(options={})
12
- @name = "Bernoulli distribution"
13
- @description = "Discrete probability distribution taking value 1 with success probability p and value 0 with failure probability 1-p."
14
- configure(options)
15
- raise Croupier::InputParamsError, "Probability of success must be in the interval [0,1]" if params[:success] > 1 || params[:success] < 0
16
- end
11
+ distribution_name "Bernoulli distribution"
12
+ distribution_description "Discrete probability distribution taking value 1 with success probability p and value 0 with failure probability 1-p."
17
13
 
18
- def generate_number
19
- binomial_1_p.generate_number
20
- end
14
+ cli_name "bernoulli"
21
15
 
22
- def default_parameters
23
- {:success => 0.5}
24
- end
16
+ cli_options({
17
+ options: [
18
+ [:success, 'success probability', {type: :float, short: "-p", default: 0.5}]
19
+ ],
20
+ banner: "Bernoulli distribution. Discrete probability distribution taking value 1 with success probability p and value 0 with failure probability 1-p."
21
+ })
25
22
 
26
- def self.cli_name
27
- "bernoulli"
23
+ enumerator do |c|
24
+ c.binomial(success: success, size: 1).to_enum.lazy
28
25
  end
29
26
 
30
- def self.cli_options
31
- {:options => [
32
- [:success, 'success probability', {:type=>:float, :short => "-p", :default => 0.5}]
33
- ],
34
- :banner => "Bernoulli distribution. Discrete probability distribution taking value 1 with success probability p and value 0 with failure probability 1-p."
35
- }
27
+ def initialize(options={})
28
+ super(options)
29
+ raise Croupier::InputParamsError, "Probability of success must be in the interval [0,1]" if params[:success] > 1 || params[:success] < 0
36
30
  end
37
-
38
- private
39
- def binomial_1_p
40
- @binomial_1_p ||= ::Croupier::Distributions::Binomial.new(:success => params[:success], :size => 1)
31
+
32
+ def success
33
+ params[:success]
41
34
  end
42
35
  end
43
36
  end
44
- end
37
+ end
@@ -8,44 +8,45 @@ module Croupier
8
8
  # probability p
9
9
  class Binomial < ::Croupier::Distribution
10
10
 
11
- def initialize(options={})
12
- @name = "Binomial distribution"
13
- @description = "Discrete probability distribution of the number of successes in a sequence of Bernoulli trials."
14
- configure(options)
15
- raise Croupier::InputParamsError, "Probability of success must be in the interval [0,1]" if params[:success] > 1 || params[:success] < 0
16
- end
11
+ distribution_name "Binomial distribution"
12
+
13
+ distribution_description "Discrete probability distribution of the number of successes in a sequence of Bernoulli trials."
14
+
15
+ cli_name "binomial"
16
+
17
+ cli_options({
18
+ options: [
19
+ [:size, 'number of trials', {type: :integer, default: 1}],
20
+ [:success, 'success probability of each trial', {type: :float, short: "-p", default: 0.5}]
21
+ ],
22
+ banner: "Binomial distribution. Discrete probability distribution of the number of successes in a sequence of Bernoulli trials."
23
+ })
17
24
 
18
- def generate_number
19
- x = -1
20
- s = 0
25
+ enumerator_block do |y|
26
+ g = ::Croupier::Distributions.geometric(success: success).to_enum.lazy
21
27
  loop do
22
- s += base_geometric.generate_number
23
- x += 1
24
- break if s > params[:size]
25
- end
26
- x
27
- end
28
+ x = -1; s = 0
29
+
30
+ begin
31
+ s += g.next
32
+ x += 1
33
+ end while s <= size
28
34
 
29
- def default_parameters
30
- {:success => 0.5, :size => 1}
35
+ y << x
36
+ end
31
37
  end
32
38
 
33
- def self.cli_name
34
- "binomial"
39
+ def initialize(options={})
40
+ super(options)
41
+ raise Croupier::InputParamsError, "Probability of success must be in the interval [0,1]" if params[:success] > 1 || params[:success] < 0
35
42
  end
36
43
 
37
- def self.cli_options
38
- {:options => [
39
- [:size, 'number of trials', {:type => :integer, :default => 1}],
40
- [:success, 'success probability of each trial', {:type=>:float, :short => "-p", :default => 0.5}]
41
- ],
42
- :banner => "Binomial distribution. Discrete probability distribution of the number of successes in a sequence of Bernoulli trials."
43
- }
44
+ def size
45
+ params[:size]
44
46
  end
45
47
 
46
- private
47
- def base_geometric
48
- @base_geometric ||= ::Croupier::Distributions::Geometric.new(success: params[:success])
48
+ def success
49
+ params[:success]
49
50
  end
50
51
 
51
52
  end
@@ -7,32 +7,35 @@ module Croupier
7
7
  #
8
8
  class Cauchy < ::Croupier::Distribution
9
9
 
10
- def initialize(options={})
11
- @name = "Cauchy distribution"
12
- @description = "Continuous probability distribution describing resonance behavior"
13
- configure(options)
14
- raise Croupier::InputParamsError, "Invalid scale value, it must be positive" unless params[:scale] > 0
15
- end
10
+ distribution_name "Cauchy distribution"
11
+
12
+ distribution_description "Continuous probability distribution describing resonance behavior"
16
13
 
17
- def inv_cdf n
18
- params[:location] + (params[:scale] * Math.tan(Math::PI * (0.5 - n)))
14
+ cli_name "cauchy"
15
+
16
+ cli_options({
17
+ options: [
18
+ [:location, 'location param', {type: :float, default:0.0}],
19
+ [:scale, 'scale param', {type: :float, default: 1.0}],
20
+ ],
21
+ banner: "Cauchy continuous distribution. Generate numbers following a Cauchy distribution with location and scale parameters"
22
+ })
23
+
24
+ inv_cdf do |n|
25
+ location + (scale * Math.tan( Math::PI * (0.5 - n)))
19
26
  end
20
27
 
21
- def default_parameters
22
- {:location => 0.0, :scale => 1.0}
28
+ def initialize(options={})
29
+ super(options)
30
+ raise Croupier::InputParamsError, "Invalid scale value, it must be positive" unless params[:scale] > 0
23
31
  end
24
32
 
25
- def self.cli_name
26
- "cauchy"
33
+ def location
34
+ params[:location]
27
35
  end
28
36
 
29
- def self.cli_options
30
- {:options => [
31
- [:location, 'location param', {:type=>:float, :default => 0.0}],
32
- [:scale, 'scale param', {:type=>:float, :default => 1.0}],
33
- ],
34
- :banner => "Cauchy continuous distribution. Generate numbers following a Cauchy distribution with location and scale parameters"
35
- }
37
+ def scale
38
+ params[:scale]
36
39
  end
37
40
  end
38
41
  end
@@ -7,10 +7,46 @@ module Croupier
7
7
  #
8
8
  class CreditCard < ::Croupier::Distribution
9
9
 
10
+ distribution_name "CreditCard distribution"
11
+
12
+ distribution_description "Generates random credit card numbers."
13
+
14
+ cli_name "credit_card"
15
+
16
+ cli_options({
17
+ options: [
18
+ [:master_card, 'master card type', {type: :boolean, default: false}],
19
+ [:american_express, 'american express card type', {type: :boolean, default: false}],
20
+ [:visa, 'visa card type', {type: :boolean, default: false}],
21
+ [:discover, 'discover card type', {type: :boolean, default: false}],
22
+ [:initial_values, 'initial values for the credit card. They will be place after card type if one is given.', {type: :string, default: ""}]
23
+ ],
24
+ banner: "Credit Card distribution. Generate random card numbers"
25
+ })
26
+
27
+ # Returns a lambda that completes
28
+ # the credit card number up to
29
+ # 15 numbers.
30
+ def fill_number
31
+ ->(n) { "#{n}#{generate_random_string(15-n.size)}"[0..14] }
32
+ end
33
+
34
+ # Returns a lambda that adds
35
+ # the checksum number
36
+ def add_checksum
37
+ ->(n) { "#{n}#{check_digit_for(n)}" }
38
+ end
39
+
40
+ enumerator do |c|
41
+ c.degenerate(constant: init).to_enum.lazy.map(&fill_number).map(&add_checksum)
42
+ end
43
+
10
44
  def initialize(options={})
11
- @name = "CreditCard distribution"
12
- @description = "Generates random credit card numbers."
13
- configure(options)
45
+ super(options)
46
+ end
47
+
48
+ def init
49
+ "#{initial_value_by_card_type}#{initial_values}"
14
50
  end
15
51
 
16
52
  def generate_number
@@ -20,20 +56,6 @@ module Croupier
20
56
  n + check_digit_for(n).to_s
21
57
  end
22
58
 
23
- def default_parameters
24
- {
25
- :master_card => false,
26
- :american_express => false,
27
- :discover => false,
28
- :visa => false,
29
- :initial_values => ""
30
- }
31
- end
32
-
33
- def self.cli_name
34
- "credit_card"
35
- end
36
-
37
59
  def check_digit_for(n)
38
60
  # Sum, every odd number should be doubled.
39
61
  # If result has two digits, they should be summed up.
@@ -68,18 +90,6 @@ module Croupier
68
90
  return 6 if params[:discover]
69
91
  ""
70
92
  end
71
-
72
- def self.cli_options
73
- {:options => [
74
- [:master_card, 'master card type', {:type=>:boolean, :default => false}],
75
- [:american_express, 'american express card type', {:type=>:boolean, :default => false}],
76
- [:visa, 'visa card type', {:type=>:boolean, :default => false}],
77
- [:discover, 'discover card type', {:type=>:boolean, :default => false}],
78
- [:initial_values, 'initial values for the credit card. They will be place after card type if one is given.', {:type=>:string, :default => ""}]
79
- ],
80
- :banner => "Credit Card distribution. Generate random card numbers"
81
- }
82
- end
83
93
  end
84
94
  end
85
95
  end