random-set 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5ad4d2dc9bcb1b5ae42bae76fbbe5cae3c29a4df
4
+ data.tar.gz: 51912ae6cdc5572a07e0ee431cab8caaba93910c
5
+ SHA512:
6
+ metadata.gz: b70d391565cc6a1ee4e4b51af0a3d78e59e518d55e38642c08c4bd83392900cf2f3a39a92ff85014f2840b082d07ddc8d7526423a21b51a1addbe9b1ab773535
7
+ data.tar.gz: bf473e2f91d385005447da3e79f1bc00bc1955b4f80b76424f61b30d81afcc7a279fb06a977a3be534463ea4a5a654cd25a94961a73895802b0fb1b00c44b7e3
data/.gitignore ADDED
@@ -0,0 +1,29 @@
1
+ # See http://help.github.com/ignore-files/ for more about ignoring files.
2
+ #
3
+ # If you find yourself ignoring temporary files generated by your text editor
4
+ # or operating system, you probably want to add a global ignore instead:
5
+ # git config --global core.excludesfile ~/.gitignore_global
6
+
7
+ # Ignore .DS_Store
8
+ .DS_Store
9
+
10
+ # Ignore the output files.
11
+ /pkg
12
+
13
+ # Ignore bundler and database config and precompiled assets
14
+ /.bundle
15
+ /.env
16
+
17
+ # Ignore all logfiles and tempfiles.
18
+ /tmp
19
+
20
+ # Ignore TextMate projects
21
+ *.tmproj
22
+ *.sublime-project
23
+ *.sublime-workspace
24
+
25
+ # Documentation files and other stuff
26
+ .yardoc
27
+ /doc
28
+ /nbproject
29
+ /coverage
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ flux
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.0.0-p247
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in random_set.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,17 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ random_set (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ rake (10.1.0)
10
+
11
+ PLATFORMS
12
+ ruby
13
+
14
+ DEPENDENCIES
15
+ bundler (~> 1.3)
16
+ rake
17
+ random_set!
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Joost Lubach
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.
data/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # RandomSet
2
+
3
+ Generates a series of data based on a template. This template may be a hash
4
+ or an array. If a hash is given, the output of this function is an array of hashes.
5
+ Conversely, if an array is given, the output is an array of arrays.
6
+
7
+ Each item in the given template corresponds to an attribute of each item in the result
8
+ set, and specifies how its data should be generated.
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ gem 'random-set'
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install random-set
23
+
24
+ ## Examples
25
+
26
+ Generate an array of tuples, where the second argument is a random number between 0 and 1:
27
+
28
+ RandomSet.generate [ (1..3), ->{ rand } ]
29
+ => [ [1, 0.156], [2, 0.782], [3, 0.249] ]
30
+
31
+ Generate some randomized trend over the last week:
32
+
33
+ RandomSet.generate :date => (Date.current - 7.days), :value => ->{ rand }
34
+
35
+ ## Counting
36
+
37
+ If at least one of the attribute templates is 'fixed-size', e.g. a range or an array,
38
+ a count is heuristically found by taking the maximum size. The value `nil` is provided
39
+ where an attribute value cannot be inferred:
40
+
41
+ RandomSet.generate [ (1..2), (1..4) ]
42
+ => [ [1,1], [1,2], [nil,3], [nil,4] ]
43
+
44
+ If you have only infinitely sized templates, you need to specify a count:
45
+
46
+ RandomSet.generate [ ->{ rand } ]
47
+ => raises CannotInferCount
48
+
49
+ RandomSet.generate 3, [ ->{ rand } ]
50
+ => [ [0.562], [0.168], [0.476] ]
51
+
52
+ ## Supported templates
53
+
54
+ The following templates are supported:
55
+
56
+ * Anything with an `each` method that returns an Enumerator.
57
+ * Procs or lambdas. One argument is passed: the number of the current iteration.
58
+ * An instance of any class that has a `next` method. If this class also has a `count` method,
59
+ it is considered a fixed-size template.
60
+
61
+ ## Built-in generators
62
+
63
+ The following built-in generators are available as templates:
64
+
65
+ * Gaussian - a Gaussian (normal distribution) random number generator.
66
+ * GaussianTrend - a trend generator using a Gaussian distribution. Each value is taken as the
67
+ mean of the next value.
68
+
69
+ To use a built-in generator, create an instance in your template:
70
+
71
+ RandomSet.generate 5, [ RandomSet::GaussianTrend.new(1000) ]
72
+ => [ [1307.878], [1397.881], [1296.988], [1929.835], [2118.800] ]
73
+
74
+ ## Integration with Faker and others
75
+
76
+ Using procs, you can easily integrate Faker-like libraries:
77
+
78
+ RandomSet.generate 3, [ ->{ Faker::Name.name } ]
79
+ => [ ["Mr. Zita Cruickshank"], ["Godfrey Grady"], ["Mrs. Simone Nikolaus"] ]
80
+
81
+ ## Contributing
82
+
83
+ 1. Fork it
84
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
85
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
86
+ 4. Push to the branch (`git push origin my-new-feature`)
87
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/lib/random-set.rb ADDED
@@ -0,0 +1 @@
1
+ require 'random_set'
@@ -0,0 +1,48 @@
1
+ module RandomSet
2
+
3
+ # Generates a Gaussian (normally distributed) random number, using the given mean and standard
4
+ # deviation.
5
+ #
6
+ # Source: http://stackoverflow.com/questions/5825680/code-to-generate-gaussian-normally-distributed-random-numbers-in-ruby
7
+ class Gaussian
8
+
9
+ # Initializes the generator.
10
+ #
11
+ # @param [Float] mean The mean.
12
+ # @param [Float] stddev The standard deviation.
13
+ # @param [Proc] rand_helper
14
+ # A proc used to generate the random number. This is Ruby's +rand+ function by default.
15
+ def initialize(mean, stddev, rand_helper = lambda { Kernel.rand })
16
+ @rand_helper = rand_helper
17
+ @mean = mean
18
+ @stddev = stddev
19
+ @valid = false
20
+ @next = 0
21
+ end
22
+
23
+ def next
24
+ if @valid then
25
+ @valid = false
26
+ return @next
27
+ else
28
+ @valid = true
29
+ x, y = self.class.gaussian(@mean, @stddev, @rand_helper)
30
+ @next = y
31
+ return x
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def self.gaussian(mean, stddev, rand)
38
+ theta = 2 * Math::PI * rand.call
39
+ rho = Math.sqrt(-2 * Math.log(1 - rand.call))
40
+ scale = stddev * rho
41
+ x = mean + scale * Math.cos(theta)
42
+ y = mean + scale * Math.sin(theta)
43
+ return x, y
44
+ end
45
+
46
+ end
47
+
48
+ end
@@ -0,0 +1,32 @@
1
+ require 'random_set/gaussian'
2
+
3
+ module RandomSet
4
+
5
+ # Generates a Gaussian trend. For each sample, a Gaussian random number is generated using
6
+ # {Gaussian}, and its value is taken as the mean value for the next value. This produces
7
+ # a natural trend.
8
+ class GaussianTrend
9
+
10
+ # Initializes the generator.
11
+ #
12
+ # @param [Float] start
13
+ # The first mean value.
14
+ # @param [Float] volatility
15
+ # This number is multiplied with the mean to provide the standard deviation. The higher
16
+ # the number, the 'wilder' the trend will become. A value of 0.2 (default) produces a
17
+ # natural trend.
18
+ # @param [Proc] rand_helper
19
+ # See {Gaussian#initialize}.
20
+ def initialize(start, volatility = 0.2, rand_helper = lambda { Kernel.rand })
21
+ @prev = start
22
+ @volatility = volatility
23
+ @rand_helper = rand_helper
24
+ end
25
+
26
+ def next
27
+ @prev = Gaussian.new(@prev, @prev * @volatility, @rand_helper).next
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -0,0 +1,94 @@
1
+ module RandomSet
2
+
3
+ # A template for the random set.
4
+ # @api internal
5
+ class Template
6
+
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
15
+
16
+ def resolve_generators(templates)
17
+ hash = {}
18
+
19
+ process = proc do |key, template|
20
+ hash[key] = create_generator(template)
21
+ end
22
+
23
+ if hash?
24
+ templates.each &process
25
+ else
26
+ templates.each_with_index { |template, index| process[index, template] }
27
+ end
28
+
29
+ hash
30
+ end
31
+
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}"
39
+ end
40
+ end
41
+
42
+ attr_reader :generators
43
+
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
50
+ end
51
+ max
52
+ end
53
+
54
+ def generate(count = self.count)
55
+ raise CannotInferCount, "no count was specified or could be inferred" unless count
56
+
57
+ data = []
58
+ count.times.each { data << generate_next(data) }
59
+ data
60
+ end
61
+
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
70
+ end
71
+ end
72
+ item
73
+ end
74
+
75
+ class CustomGenerator
76
+
77
+ def initialize(block)
78
+ @block = block
79
+ @iteration = 0
80
+ end
81
+
82
+ attr_reader :block
83
+
84
+ def next
85
+ block.call @iteration
86
+ ensure
87
+ @iteration += 1
88
+ end
89
+
90
+ end
91
+
92
+ end
93
+
94
+ end
@@ -0,0 +1,3 @@
1
+ module RandomSet
2
+ VERSION = "0.0.2"
3
+ end
data/lib/random_set.rb ADDED
@@ -0,0 +1,30 @@
1
+ module RandomSet
2
+
3
+ class UnsupportedTemplate < RuntimeError; end
4
+ class CannotInferCount < RuntimeError; end
5
+
6
+ class << self
7
+
8
+ # @!method generate([count], template)
9
+ #
10
+ # Generates a series of data based on the given template. This template may be a hash
11
+ # or an array. If a hash is given, the output of this function is an array of hashes.
12
+ # Conversely, if an array is given, the output is an array of arrays.
13
+ #
14
+ # @param [Fixnum] count A count. Leave this out if the count can be inferred.
15
+ # @param [Hash|Array] template The generator template.
16
+ # @return [Array] The generated data.
17
+ #
18
+ # @raise [UnsupportedTemplated] If any of the provided templates was not supported.
19
+ # @raise [CannotInferCount] If no count was specified, and no count could be inferred.
20
+ def generate(*args)
21
+ raise ArgumentError, "template required" if args.empty?
22
+ raise ArgumentError, "too many arguments (1..2 expected)" if args.length > 2
23
+ Template.new(args.pop).generate *args
24
+ end
25
+
26
+ end
27
+ end
28
+
29
+ require 'random_set/template'
30
+ require 'random_set/gaussian_trend'
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'random_set/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "random-set"
8
+ spec.version = RandomSet::VERSION
9
+ spec.authors = ["Joost Lubach"]
10
+ spec.email = ["joost@yoazt.com"]
11
+ spec.description = %q{Generates a series of data based on a template.}
12
+ spec.summary = %q{Generates a series of data based on a template.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: random-set
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Joost Lubach
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Generates a series of data based on a template.
42
+ email:
43
+ - joost@yoazt.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - .ruby-gemset
50
+ - .ruby-version
51
+ - Gemfile
52
+ - Gemfile.lock
53
+ - LICENSE.txt
54
+ - README.md
55
+ - Rakefile
56
+ - lib/random-set.rb
57
+ - lib/random_set.rb
58
+ - lib/random_set/gaussian.rb
59
+ - lib/random_set/gaussian_trend.rb
60
+ - lib/random_set/template.rb
61
+ - lib/random_set/version.rb
62
+ - random-set.gemspec
63
+ homepage: ''
64
+ licenses:
65
+ - MIT
66
+ metadata: {}
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 2.1.4
84
+ signing_key:
85
+ specification_version: 4
86
+ summary: Generates a series of data based on a template.
87
+ test_files: []
88
+ has_rdoc: