junklet 1.0.1 → 1.0.2
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 +8 -8
- data/Gemfile.lock +1 -1
- data/README.md +43 -0
- data/lib/junklet/version.rb +1 -1
- data/lib/junklet.rb +83 -8
- data/spec/lib/junklet_spec.rb +73 -5
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
Zjc3YzlmNzVjYTc3YmZhNTIwZjZlNTE4Y2I1ZTQ2YWM0ZmNmODk3ZQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NTI1YTRjZWJkMmFiMmI3ZWNhOGM2NTBhNDRkZmNjYWZiMzJjNGM4ZQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
OGM0ZDRjYTkxYjdhNTdlNzA5YTM3MjU5MGEyZDk3ZWQwYTQ0YjU5NjczMGE2
|
10
|
+
ZGU0NmIxNjk4ZDc1Yzg5NDAxOTU2NTM4NmJlNTE3NjIwMmM4NWZhMDM2MTNk
|
11
|
+
OTFmN2FiNjAwMThiYTBlNTFkYTM3M2I4NjE5NDQzMDZiZjIxZjk=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
OWIxNDM5ZGUyOWRhODg1YmM5NDFiMWZhMjNjNGY0MTRlZGQ1ZDNmY2JhNGJh
|
14
|
+
Nzk5MzVlZTk4NDJhYWIwM2E0ZDUyNmI1NzEyZGQ2NGIyYjM0M2VhOWM5YTAx
|
15
|
+
MmJiNTg0MGY3ZDY2NGNlNjJlYTU4NmViMmM2OWY5ZmNjZjlhYmU=
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -119,6 +119,49 @@ This will have the same effect as calling `let` on the named fields
|
|
119
119
|
and setting the fieldname and a 32-byte hex string (a uuid with
|
120
120
|
hyphens removed) to be the memoized value.
|
121
121
|
|
122
|
+
|
123
|
+
|
124
|
+
# Finer Control / Custom Types
|
125
|
+
|
126
|
+
The `junk` method now has MUCH finer-grained control, though this
|
127
|
+
hasn't been pushed up to junklet yet.
|
128
|
+
|
129
|
+
|
130
|
+
`junk <type> [options]`
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
junk(:int) # returns a random, positive ruby Fixnum between 0 and
|
134
|
+
# 2**62-1.
|
135
|
+
junk(:int, min: 5, max: 9) # returns a number from 5 to 9
|
136
|
+
junk(:int, max: 1) # returns 0 or 1
|
137
|
+
|
138
|
+
junk(:bool) # returns true or false
|
139
|
+
|
140
|
+
junk([:a, :b, :c]) # samples from the Array
|
141
|
+
junk(('A'..'Z')) # samples from the range.
|
142
|
+
|
143
|
+
# Memory warning: calls to_a on range first, so if you want a number
|
144
|
+
# from 100000 to 999999, favor junk(:int, min: 100000, max: 999999)
|
145
|
+
# instead.
|
146
|
+
|
147
|
+
junk ->{ your_own_random_thing_here }
|
148
|
+
|
149
|
+
# Also note that all types also take an `exclude` option, which can be
|
150
|
+
# a value, an array, or a proc. These all return even numbers:
|
151
|
+
|
152
|
+
junk :int, min: 2, max: 4, exclude: 3
|
153
|
+
junk :int, min: 2, max: 10, exclude: [3,5,7,9]
|
154
|
+
junk :int, min: 2, max: 100, exclude: ->(x) { x % 2 == 1 }
|
155
|
+
|
156
|
+
# And remember that junk is at the same level of precedence as let, so
|
157
|
+
# the following ALSO return even numbers:
|
158
|
+
|
159
|
+
let(:three) { 3 }
|
160
|
+
let(:evens) { junk :int, min: 2, max: 4, exclude: three }
|
161
|
+
let(:two_or_four) { junk :int, min: 2, max: 4, exclude: ->(x){ !evens.include?(x) }
|
162
|
+
|
163
|
+
```
|
164
|
+
|
122
165
|
# TODO
|
123
166
|
|
124
167
|
* Formats - The original motivation for Junklet is to encapsulate the
|
data/lib/junklet/version.rb
CHANGED
data/lib/junklet.rb
CHANGED
@@ -5,12 +5,17 @@ module RSpec
|
|
5
5
|
module MemoizedHelpers
|
6
6
|
module ClassMethods
|
7
7
|
def junklet(*args)
|
8
|
+
# TODO: figure out how to use this to wrap junk in junklet,
|
9
|
+
# so that junklet can basically have all the same options as
|
10
|
+
# junk does. E.g. junklet :ddid, :pcn, :group, type: :int,
|
11
|
+
# min: 100000, max: 999999, etc, and you'd get back 3
|
12
|
+
# junklets of 6-digit numbers.
|
8
13
|
opts = args.size > 1 && !args.last.is_a?(Symbol) && args.pop || {}
|
9
14
|
|
10
15
|
names = args.map(&:to_s)
|
11
16
|
|
12
17
|
if opts.key?(:separator)
|
13
|
-
names = names.map {|name| name.gsub(/_/, opts[:separator])
|
18
|
+
names = names.map {|name| name.gsub(/_/, opts[:separator])}
|
14
19
|
end
|
15
20
|
|
16
21
|
args.zip(names).each do |arg, name|
|
@@ -19,14 +24,84 @@ module RSpec
|
|
19
24
|
end
|
20
25
|
end
|
21
26
|
|
22
|
-
def junk(
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
def junk(*args)
|
28
|
+
# TODO: It's long past time to extract this....
|
29
|
+
|
30
|
+
# args.first can be
|
31
|
+
# - an integer indicating the size of the hex string to return
|
32
|
+
# - a symbol denoting the base type, e.g. :int
|
33
|
+
# - an array to sample from
|
34
|
+
# - a range or Enumerable to sample from. WARNING: will call
|
35
|
+
# .to_a on it first, which might be expensive
|
36
|
+
# - a generator Proc which, when called, will generate the
|
37
|
+
# value to use.
|
38
|
+
#
|
39
|
+
# args.rest is a hash of options:
|
40
|
+
# - sequence: Proc or Array of values to choose from.
|
41
|
+
# - exclude: value, array of values, or proc to exclude. If a
|
42
|
+
# Proc is given, it takes the value generated and returns
|
43
|
+
# true if the value should be excluded.
|
44
|
+
#
|
45
|
+
# - for int:
|
46
|
+
# - min: minimum number to return. Default: 0
|
47
|
+
# - max: upper limit of range
|
48
|
+
# - exclude: number, array of numbers, or proc to
|
49
|
+
# exclude. If Proc is provided, tests the number against
|
50
|
+
# the Proc an excludes it if the Proc returns true. This
|
51
|
+
# is implemented except for the proc.
|
52
|
+
|
53
|
+
# FIXME: Raise Argument error unless *args.size is 0-2
|
54
|
+
# FIXME: If arg 1 is a hash, it's the options hash, raise
|
55
|
+
# ArgumentError unless args.size == 1
|
56
|
+
# FIXME: If arg 2 present, Raise Argument error unless it's a
|
57
|
+
# hash.
|
58
|
+
# FIXME: Figure out what our valid options are and parse them;
|
59
|
+
# raise errors if present.
|
60
|
+
|
61
|
+
classes = [Symbol, Array, Enumerable, Proc]
|
62
|
+
if args.size > 0 && classes.any? {|klass| args.first.is_a?(klass) }
|
63
|
+
type = args.shift
|
64
|
+
opts = args.last || {}
|
65
|
+
excluder = if opts[:exclude]
|
66
|
+
if opts[:exclude].is_a?(Proc)
|
67
|
+
opts[:exclude]
|
68
|
+
else
|
69
|
+
->(x) { Array(opts[:exclude]).include?(x) }
|
70
|
+
end
|
71
|
+
else
|
72
|
+
->(x) { false }
|
73
|
+
end
|
74
|
+
|
75
|
+
# TODO: Refactor me. Seriously, this is a functional
|
76
|
+
# programming version of the strategy pattern. Wouldn't it
|
77
|
+
# be neat if we had some kind of object-oriented language
|
78
|
+
# available here?
|
79
|
+
case type
|
80
|
+
when :int
|
81
|
+
# Fun fact: you can get back an arbitrarily large number
|
82
|
+
# by specifying a max value >= 2**62 so that Ruby promotes
|
83
|
+
# it to a BigNum.
|
84
|
+
min = opts[:min] || 0
|
85
|
+
max = (opts[:max] || 2**62-2) + 1
|
86
|
+
min,max = max,min if min>max
|
87
|
+
|
88
|
+
generator = -> { rand(max-min) + min }
|
89
|
+
when :bool
|
90
|
+
generator = -> { [true, false].sample }
|
91
|
+
when Array, Enumerable
|
92
|
+
generator = -> { type.to_a.sample }
|
93
|
+
when Proc
|
94
|
+
generator = type
|
95
|
+
else
|
96
|
+
raise "Unrecognized junk type: '#{type}'"
|
97
|
+
end
|
98
|
+
|
99
|
+
begin
|
100
|
+
val = generator.call
|
101
|
+
end while excluder.call(val)
|
102
|
+
val
|
29
103
|
else
|
104
|
+
size = args.first.is_a?(Numeric) ? args.first : 32
|
30
105
|
# hex returns size*2 digits, because it returns a 0..255 byte
|
31
106
|
# as a hex pair. But when we want junt, we want *bytes* of
|
32
107
|
# junk. Get (size+1)/2 chars, which will be correct for even
|
data/spec/lib/junklet_spec.rb
CHANGED
@@ -71,12 +71,80 @@ describe Junklet do
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
-
context "with type:
|
75
|
-
let(:
|
76
|
-
it "returns
|
77
|
-
expect
|
78
|
-
expect { (widget_id.to_s.size).to eq(15) }
|
74
|
+
context "with type: array" do
|
75
|
+
let(:junk_ray) { junk [:a, :b, :c] }
|
76
|
+
it "returns a random element of the array" do
|
77
|
+
expect([:a, :b, :c]).to include(junk_ray)
|
79
78
|
end
|
79
|
+
|
80
|
+
context "with excludes" do
|
81
|
+
let(:junk_ray) { junk [:a, :b, :c], exclude: [:a, :b] }
|
82
|
+
specify { expect(junk_ray).to eq(:c) }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "with type: Proc" do
|
87
|
+
let(:junk_proc) { junk(->{ rand(3) }) }
|
88
|
+
specify { expect([0,1,2]).to include(junk_proc) }
|
89
|
+
|
90
|
+
context "with excludes" do
|
91
|
+
let(:junk_proc) { junk(->{ rand(3) }, exclude: [0,2]) }
|
92
|
+
specify { expect(junk_proc).to eq(1) }
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "with type: enumerable" do
|
97
|
+
let(:junk_list) { junk (0..3) }
|
98
|
+
it "returns a random element of the array" do
|
99
|
+
expect([0,1,2,3]).to include(junk_list)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context "with type: :int" do
|
104
|
+
let(:junk_integer) { junk :int }
|
105
|
+
it "returns a random positive Fixnum" do
|
106
|
+
expect { (junk_integer).to be_a Fixnum }
|
107
|
+
end
|
108
|
+
|
109
|
+
context "with min and max values" do
|
110
|
+
let(:coin) { junk :int, min: 0, max: 1 }
|
111
|
+
specify { expect([0,1]).to include(coin) }
|
112
|
+
end
|
113
|
+
|
114
|
+
context "with exclude proc" do
|
115
|
+
let(:junk_evens) { junk :int, min: 0, max: 10, exclude: ->(x) { x % 2 == 1 } }
|
116
|
+
specify { expect(junk_evens % 2).to eq(0) }
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context "with type: :bool" do
|
121
|
+
let(:junk_bool) { junk :bool }
|
122
|
+
specify { expect([true, false]).to include(junk_bool) }
|
123
|
+
|
124
|
+
context "with excludes" do
|
125
|
+
let(:junk_bool) { junk :bool, exclude: true }
|
126
|
+
specify { expect(junk_bool).to eq(false) }
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# begin
|
131
|
+
# $caught_bad_junklet_error = false
|
132
|
+
# junklet :cheesy_bad_junklet, cheese: true
|
133
|
+
# rescue INVALID_JUNKLET_ERROR => e
|
134
|
+
# raise "junklet got invalid option" unless e.message == "junklet options must be one of #{VALID_JUNKLET_ARGS.map(&:inspect) * ', '}"
|
135
|
+
# $caught_bad_junklet_error = true
|
136
|
+
# else
|
137
|
+
# raise "junklet got an invalid argument but didn't catch it" unless $caught_bad_junklet_error
|
138
|
+
# end
|
139
|
+
|
140
|
+
context "with exclude: val" do
|
141
|
+
let(:heads) { 0 }
|
142
|
+
let(:tails) { 1 }
|
143
|
+
let(:coin_heads) { junk :int, max: 1, exclude: tails }
|
144
|
+
let(:coin_tails) { junk :int, max: 1, exclude: heads }
|
145
|
+
|
146
|
+
specify { expect(coin_heads).to eq(heads) }
|
147
|
+
specify { expect(coin_tails).to eq(tails) }
|
80
148
|
end
|
81
149
|
end
|
82
150
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: junklet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dave Brady
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-02-
|
11
|
+
date: 2015-02-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|