random-set 0.0.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5ad4d2dc9bcb1b5ae42bae76fbbe5cae3c29a4df
4
- data.tar.gz: 51912ae6cdc5572a07e0ee431cab8caaba93910c
3
+ metadata.gz: de80dcedc3dbdcc3bbe1257059617cbda64f2c7a
4
+ data.tar.gz: 13005ce042de59de432963a064e481952bfe8e97
5
5
  SHA512:
6
- metadata.gz: b70d391565cc6a1ee4e4b51af0a3d78e59e518d55e38642c08c4bd83392900cf2f3a39a92ff85014f2840b082d07ddc8d7526423a21b51a1addbe9b1ab773535
7
- data.tar.gz: bf473e2f91d385005447da3e79f1bc00bc1955b4f80b76424f61b30d81afcc7a279fb06a977a3be534463ea4a5a654cd25a94961a73895802b0fb1b00c44b7e3
6
+ metadata.gz: a6eb17de0c6ec5c0409f8a726c1cc55d9457d00409ef0f26026080a705d05ead885f5d2b8db3a59371bef0880b51d81407238ecbf4fc571b5a06aa6c0a716fab
7
+ data.tar.gz: 8e6d39b2dabb9d73f64c8b12fb08304f781495703b6584caaad002e23eae29c04e45b408e1f8da9fcd96a92bb7ec5404e6ad8941848181e99af0a5aaed389e7c
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ script: bundle exec rake
2
+ rvm:
3
+ - 2.0.0
4
+ branches:
5
+ only:
6
+ - master
data/Gemfile.lock CHANGED
@@ -1,12 +1,26 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- random_set (0.0.1)
4
+ random-set (1.0.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
+ diff-lcs (1.2.5)
10
+ multi_json (1.8.2)
9
11
  rake (10.1.0)
12
+ rspec (2.14.1)
13
+ rspec-core (~> 2.14.0)
14
+ rspec-expectations (~> 2.14.0)
15
+ rspec-mocks (~> 2.14.0)
16
+ rspec-core (2.14.7)
17
+ rspec-expectations (2.14.4)
18
+ diff-lcs (>= 1.1.3, < 2.0)
19
+ rspec-mocks (2.14.4)
20
+ simplecov (0.7.1)
21
+ multi_json (~> 1.0)
22
+ simplecov-html (~> 0.7.1)
23
+ simplecov-html (0.7.1)
10
24
 
11
25
  PLATFORMS
12
26
  ruby
@@ -14,4 +28,6 @@ PLATFORMS
14
28
  DEPENDENCIES
15
29
  bundler (~> 1.3)
16
30
  rake
17
- random_set!
31
+ random-set!
32
+ rspec
33
+ simplecov
data/README.md CHANGED
@@ -7,6 +7,8 @@ Conversely, if an array is given, the output is an array of arrays.
7
7
  Each item in the given template corresponds to an attribute of each item in the result
8
8
  set, and specifies how its data should be generated.
9
9
 
10
+ [<img src="https://secure.travis-ci.org/yoazt/random-set.png?branch=master" alt="Build Status" />](http://travis-ci.org/yoazt/random-set)
11
+
10
12
  ## Installation
11
13
 
12
14
  Add this line to your application's Gemfile:
@@ -54,7 +56,7 @@ If you have only infinitely sized templates, you need to specify a count:
54
56
  The following templates are supported:
55
57
 
56
58
  * Anything with an `each` method that returns an Enumerator.
57
- * Procs or lambdas. One argument is passed: the number of the current iteration.
59
+ * Procs or lambdas. One (optional) argument is passed: the number of the current iteration.
58
60
  * An instance of any class that has a `next` method. If this class also has a `count` method,
59
61
  it is considered a fixed-size template.
60
62
 
@@ -1,77 +1,92 @@
1
1
  module RandomSet
2
2
 
3
- # A template for the random set.
4
- # @api internal
3
+ # @api private
5
4
  class Template
6
5
 
7
- def initialize(templates)
8
- @hash = templates.is_a?(Hash)
9
- @generators = resolve_generators(templates)
10
- end
11
-
12
- def hash?
13
- @hash
14
- end
6
+ ######
7
+ # Initialization & attributes
15
8
 
16
- def resolve_generators(templates)
17
- hash = {}
18
-
19
- process = proc do |key, template|
20
- hash[key] = create_generator(template)
9
+ def initialize(templates)
10
+ @hash = templates.is_a?(Hash)
11
+ @generators = resolve_generators(templates)
21
12
  end
22
13
 
23
- if hash?
24
- templates.each &process
25
- else
26
- templates.each_with_index { |template, index| process[index, template] }
14
+ def hash?
15
+ @hash
27
16
  end
28
17
 
29
- hash
30
- end
18
+ attr_reader :generators
31
19
 
32
- def create_generator(template)
33
- case template
34
- when nil then nil
35
- when ->(t){ t.respond_to?(:next) } then template
36
- when ->(t){ t.respond_to?(:each) } then template.each
37
- when Proc then CustomGenerator.new(template)
38
- else raise UnsupportedTemplate, "cannot create a generator for a template of class #{template.class}"
20
+ def count
21
+ max = nil
22
+ generators.each do |_key, generator|
23
+ next unless generator && generator.respond_to?(:count)
24
+ max = [ max.to_i, generator.count ].max
25
+ end
26
+ max
39
27
  end
40
- end
41
28
 
42
- attr_reader :generators
29
+ ######
30
+ # Generation
31
+
32
+ def generate(count = self.count)
33
+ raise CannotInferCount, "no count was specified or could be inferred" unless count
43
34
 
44
- # Gives a count for the items in this template. If no count can be inferred, +nil+ is returned.
45
- def count
46
- max = nil
47
- generators.each do |_key, generator|
48
- next unless generator && generator.respond_to?(:count)
49
- max = [ max.to_i, generator.count ].max
35
+ data = []
36
+ count.times.each { data << generate_next(data) }
37
+ data
50
38
  end
51
- max
52
- end
53
39
 
54
- def generate(count = self.count)
55
- raise CannotInferCount, "no count was specified or could be inferred" unless count
40
+ ######
41
+ # Support
56
42
 
57
- data = []
58
- count.times.each { data << generate_next(data) }
59
- data
60
- end
43
+ private
44
+
45
+ def resolve_generators(templates)
46
+ hash = {}
47
+
48
+ process = proc do |key, template|
49
+ hash[key] = create_generator(template)
50
+ end
51
+
52
+ if hash?
53
+ templates.each &process
54
+ else
55
+ templates.each_with_index { |template, index| process[index, template] }
56
+ end
57
+
58
+ hash
59
+ end
60
+
61
+ def create_generator(template)
62
+ case template
63
+ when nil then nil
64
+ when ->(t){ t.respond_to?(:next) } then template
65
+ when ->(t){ t.respond_to?(:each) } then template.each
66
+ when Proc then CustomGenerator.new(template)
67
+ else raise UnsupportedTemplate, "cannot create a generator for a template of class #{template.class}"
68
+ end
69
+ end
61
70
 
62
- def generate_next(data)
63
- item = hash? ? {} : []
64
- generators.each do |key, generator|
65
- begin
66
- item[key] = generator.try(:next)
67
- rescue StopIteration
68
- # If some enumerator came to the end, we just leave the rest of the keys blank.
69
- item[key] = nil
71
+ def generate_next(data)
72
+ item = hash? ? {} : []
73
+ generators.each do |key, generator|
74
+ begin
75
+ item[key] = generator ? generator.next : nil
76
+ rescue StopIteration
77
+ # If some enumerator came to the end, we just leave the rest of the keys blank.
78
+ item[key] = nil
79
+ end
70
80
  end
81
+ item
71
82
  end
72
- item
83
+
73
84
  end
74
85
 
86
+ ######
87
+ # CustomGenerator class
88
+
89
+ # @api private
75
90
  class CustomGenerator
76
91
 
77
92
  def initialize(block)
@@ -82,13 +97,15 @@ module RandomSet
82
97
  attr_reader :block
83
98
 
84
99
  def next
85
- block.call @iteration
100
+ if block.arity == 1
101
+ block.call @iteration
102
+ else
103
+ block.call
104
+ end
86
105
  ensure
87
106
  @iteration += 1
88
107
  end
89
108
 
90
109
  end
91
110
 
92
- end
93
-
94
111
  end
@@ -1,3 +1,3 @@
1
1
  module RandomSet
2
- VERSION = "0.0.2"
2
+ VERSION = "1.0.0"
3
3
  end
data/random-set.gemspec CHANGED
@@ -20,4 +20,6 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_development_dependency "bundler", "~> 1.3"
22
22
  spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "simplecov"
23
25
  end
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+
3
+ describe "RandomSet generation" do
4
+
5
+ context "specifying an empty template" do
6
+
7
+ it "should require a count" do
8
+ expect{ RandomSet.generate([]) }.to raise_error(RandomSet::CannotInferCount)
9
+ end
10
+
11
+ it "should output X empty records" do
12
+ data = RandomSet.generate(5, [])
13
+
14
+ expect(data).to have(5).items
15
+ expect(data[0]).to be_empty
16
+ expect(data[1]).to be_empty
17
+ expect(data[2]).to be_empty
18
+ expect(data[3]).to be_empty
19
+ expect(data[4]).to be_empty
20
+ end
21
+
22
+ end
23
+
24
+ context "specifying a hash template" do
25
+
26
+ it "should output a list of hashes" do
27
+ expect(RandomSet.generate(5, {})).to eql([ {}, {}, {}, {}, {} ])
28
+ end
29
+
30
+ it "should fill in key-by-key" do
31
+ expect(RandomSet.generate(2, { :name => -> { 'Test' }, :age => (1..2) })).to eql([
32
+ { :name => 'Test', :age => 1 },
33
+ { :name => 'Test', :age => 2 }
34
+ ])
35
+ end
36
+
37
+ end
38
+
39
+ context "specifying an array template" do
40
+
41
+ it "should output a list of arrays" do
42
+ expect(RandomSet.generate(5, [])).to eql([ [], [], [], [], [] ])
43
+ end
44
+
45
+ it "should fill in index by index" do
46
+ expect(RandomSet.generate(2, [ -> { 'Test' }, (1..2) ])).to eql([
47
+ ['Test', 1], ['Test', 2]
48
+ ])
49
+ end
50
+
51
+ end
52
+
53
+ describe 'full example' do
54
+
55
+ let(:custom_generator1) do
56
+ Class.new do
57
+ def initialize
58
+ @iteration = 0
59
+ end
60
+ def next
61
+ "Iteration #{@iteration}"
62
+ ensure
63
+ @iteration += 1
64
+ end
65
+ end.new
66
+ end
67
+
68
+ let :custom_generator2 do
69
+ Class.new do
70
+ def next; 'Same' end
71
+ def count; 3 end
72
+ end.new
73
+ end
74
+
75
+ it "should infer the count from all generators that support counts" do
76
+ data = RandomSet.generate([custom_generator1, custom_generator2])
77
+ expect(data).to have(3).items
78
+ end
79
+
80
+ it "should generate ranges, arrays, procs, and custom generators" do
81
+ data = RandomSet.generate(5, [ custom_generator1, (1..10), [1,2,3], ->(n) { "Item #{n}" } ])
82
+ expect(data).to eql([
83
+ ['Iteration 0', 1, 1, 'Item 0'],
84
+ ['Iteration 1', 2, 2, 'Item 1'],
85
+ ['Iteration 2', 3, 3, 'Item 2'],
86
+ ['Iteration 3', 4, nil, 'Item 3'],
87
+ ['Iteration 4', 5, nil, 'Item 4']
88
+ ])
89
+ end
90
+
91
+
92
+ end
93
+
94
+
95
+ end
@@ -0,0 +1,125 @@
1
+ require 'spec_helper'
2
+ include RandomSet
3
+
4
+ describe Template do
5
+
6
+ let(:template) { Template.new([]) }
7
+
8
+ describe '#hash?' do
9
+ it "should be true if the passed in argument was a hash" do
10
+ expect(Template.new({})).to be_hash
11
+ end
12
+ it "should be false if anything else was passed in" do
13
+ expect(Template.new([])).not_to be_hash
14
+ end
15
+ end
16
+
17
+ describe '#generators' do
18
+
19
+ it "should be a hash, regardless of the template's input" do
20
+ expect(Template.new({}).generators).to be_a(Hash)
21
+ expect(Template.new([]).generators).to be_a(Hash)
22
+ end
23
+
24
+ it "should contain a resolved generator for each item in the templates" do
25
+ item1 = (1..5)
26
+ item2 = ->{}
27
+
28
+ generators = Template.new([item1, item2]).generators
29
+ expect(generators).to have(2).items
30
+ expect(generators[0]).to be_a(Enumerator)
31
+ expect(generators[1]).to be_a(CustomGenerator)
32
+ end
33
+
34
+ it "should contain a resolved generator for each item in the templates" do
35
+ item1 = (1..5)
36
+ item2 = ->{}
37
+
38
+ generators = Template.new(:item1 => item1, :item2 => item2).generators
39
+ expect(generators).to have(2).items
40
+ expect(generators[:item1]).to be_a(Enumerator)
41
+ expect(generators[:item2]).to be_a(CustomGenerator)
42
+ end
43
+
44
+ end
45
+
46
+ describe '#count' do
47
+ it "should be the maximum count for all generators that return a count" do
48
+ generator1 = double(:count => 2, :next => nil)
49
+ generator2 = double(:count => 5, :next => nil)
50
+ generator3 = double(:next => nil)
51
+ template = Template.new([generator1, generator2, generator3])
52
+ expect(template.count).to eql(5)
53
+ end
54
+
55
+ it "should return nil if no generators had a count method" do
56
+ generator1 = double(:next => nil)
57
+ generator2 = double(:next => nil)
58
+ generator3 = double(:next => nil)
59
+ template = Template.new([generator1, generator2, generator3])
60
+ expect(template.count).to be_nil
61
+ end
62
+ end
63
+
64
+ describe '#generate' do
65
+ let(:template) { Template.new([]) }
66
+
67
+ it "should raise an error if no count was provided, and no count could be inferred" do
68
+ expect(template).to receive(:count).and_return(nil)
69
+ expect{ template.generate }.to raise_error(CannotInferCount, 'no count was specified or could be inferred')
70
+ end
71
+
72
+ it "should output <template.count> records if no count is specified" do
73
+ expect(template).to receive(:count).and_return(5)
74
+ expect(template.generate).to have(5).items
75
+ end
76
+
77
+ it "should output <count> records if a count is specified" do
78
+ allow(template).to receive(:count).and_return(5)
79
+ expect(template.generate(10)).to have(10).items
80
+ end
81
+
82
+ # Other generation examples in the integration specs.
83
+ end
84
+
85
+ describe 'generator resolution' do
86
+
87
+ it "should resolve a range to its enumerator" do
88
+ generator = Template.new([ (1..5) ]).generators[0]
89
+ expect(generator).to be_a(Enumerator)
90
+ expect(generator.map { |i| i }).to eql([1,2,3,4,5])
91
+ end
92
+
93
+ it "should resolve an array to its enumerator" do
94
+ generator = Template.new([ [1,2,3] ]).generators[0]
95
+ expect(generator).to be_a(Enumerator)
96
+ expect(generator.map { |i| i }).to eql([1,2,3])
97
+ end
98
+
99
+ it "should resolve a block into a CustomGenerator" do
100
+ block = ->{}
101
+ generator = Template.new([ block ]).generators[0]
102
+ expect(generator).to be_a(CustomGenerator)
103
+ expect(generator.block).to be(block)
104
+ end
105
+
106
+ it "should resolve anything with an 'each' method to the result of that method" do
107
+ enumerator = double()
108
+ generator = Template.new([ double(:each => enumerator) ]).generators[0]
109
+ expect(generator).to be(enumerator)
110
+ end
111
+
112
+ it "should resolve anything with a 'next' method to itself" do
113
+ generator = double(:next => nil)
114
+ expect(Template.new([ generator ]).generators[0]).to be(generator)
115
+ end
116
+
117
+ it "should raise an error for something else" do
118
+ expect{ Template.new([ Object.new ]) }
119
+ .to raise_error(UnsupportedTemplate, "cannot create a generator for a template of class Object")
120
+ end
121
+
122
+ end
123
+
124
+
125
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe RandomSet do
4
+
5
+ describe '.generate' do
6
+
7
+ it "should require a template argument" do
8
+ expect{ RandomSet.generate }
9
+ .to raise_error(ArgumentError, "template required")
10
+ end
11
+
12
+ it "should not accept more than two arguments" do
13
+ expect{ RandomSet.generate :one, :two, :template }
14
+ .to raise_error(ArgumentError, "too many arguments (1..2 expected)")
15
+ end
16
+
17
+ it "should create a template from the last argument and call its generate with the rest of the arguments" do
18
+ template = double(:template)
19
+ expect(RandomSet::Template).to receive(:new).with(:template).and_return(template)
20
+
21
+ result = double(:result)
22
+ expect(template).to receive(:generate).with(10).and_return(result)
23
+ expect(RandomSet.generate 10, :template).to be(result)
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,18 @@
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_filter "spec/"
4
+ add_filter "gaussian*" # cannot really test randomizers
5
+ end
6
+
7
+ require 'random-set'
8
+ require 'rspec/autorun'
9
+
10
+ RSpec.configure do |config|
11
+ config.mock_with :rspec do |config|
12
+ config.syntax = :expect
13
+ end
14
+ end
15
+
16
+ # Requires supporting ruby files with custom matchers and macros, etc,
17
+ # in spec/support/ and its subdirectories.
18
+ Dir[File.expand_path("../support/**/*.rb", __FILE__)].each {|f| require f}
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: random-set
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joost Lubach
@@ -38,6 +38,34 @@ dependencies:
38
38
  - - '>='
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
41
69
  description: Generates a series of data based on a template.
42
70
  email:
43
71
  - joost@yoazt.com
@@ -48,6 +76,7 @@ files:
48
76
  - .gitignore
49
77
  - .ruby-gemset
50
78
  - .ruby-version
79
+ - .travis.yml
51
80
  - Gemfile
52
81
  - Gemfile.lock
53
82
  - LICENSE.txt
@@ -60,6 +89,10 @@ files:
60
89
  - lib/random_set/template.rb
61
90
  - lib/random_set/version.rb
62
91
  - random-set.gemspec
92
+ - spec/generation_spec.rb
93
+ - spec/random_set/template_spec.rb
94
+ - spec/random_set_spec.rb
95
+ - spec/spec_helper.rb
63
96
  homepage: ''
64
97
  licenses:
65
98
  - MIT
@@ -84,5 +117,9 @@ rubygems_version: 2.1.4
84
117
  signing_key:
85
118
  specification_version: 4
86
119
  summary: Generates a series of data based on a template.
87
- test_files: []
120
+ test_files:
121
+ - spec/generation_spec.rb
122
+ - spec/random_set/template_spec.rb
123
+ - spec/random_set_spec.rb
124
+ - spec/spec_helper.rb
88
125
  has_rdoc: