rspec-junklet 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +34 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +47 -0
- data/LICENSE +22 -0
- data/README.md +314 -0
- data/lib/junklet/junk.rb +118 -0
- data/lib/junklet/junklet.rb +25 -0
- data/lib/junklet/version.rb +3 -0
- data/lib/junklet.rb +9 -0
- data/lib/line.rb +44 -0
- data/rspec-junklet.gemspec +26 -0
- data/spec/fixtures/block1_after.txt +6 -0
- data/spec/fixtures/block1_before.txt +7 -0
- data/spec/fixtures/combined_after.txt +6 -0
- data/spec/fixtures/combined_before.txt +9 -0
- data/spec/fixtures/embedded_after.txt +8 -0
- data/spec/fixtures/embedded_before.txt +9 -0
- data/spec/fixtures/mixed_code_after.txt +47 -0
- data/spec/fixtures/mixed_code_before.txt +46 -0
- data/spec/fixtures/old_skool_after.txt +6 -0
- data/spec/fixtures/old_skool_before.txt +7 -0
- data/spec/lib/junklet/junk_spec.rb +152 -0
- data/spec/lib/junklet/junklet_spec.rb +41 -0
- data/spec/lib/junklet_spec.rb +173 -0
- data/spec/lib/line_spec.rb +76 -0
- data/spec/spec_helper.rb +45 -0
- metadata +157 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZWQwYjZkZmNlNjlkNmM0MTE2YTMyNzBmYTEwMjU0MThjMjNlYzUzMA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MjQwNmUwNzQxYTljYWQ1NjhiMTgxNzU0NTk0NzNjNTk4MDhkYjdkNg==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZTFlNmUzYTRhNzgzNjQyNjViZjA4YWNmYzI5Mjk4NWQ3N2VmNDhkYjZmNzIx
|
10
|
+
NmM5MWE5MDkzNzk1Y2E2YmM2MTEyM2U2YWI0YTU4NjVkOTA1MTdiYjNhZGFj
|
11
|
+
MThhZjU2MWY2ZDRhYTI2ODQ4MTI2YzJkZmM1NTM0ODJiM2Q1YmQ=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
OWY2NjNiNmY2ZDM1NTVlNWNmODNmZDIxMGNjODI1N2Y2M2MzMmJkOWY4Nzc4
|
14
|
+
NDY1NTFjZmFjZjU1NjA2YmJiZWI3NzUyYzQ0ZjZmZjYxNjIxYmJlMThkM2Y5
|
15
|
+
OTYyMjA0ZjEwMTk5MGU1ZmQ2N2UxYWZjMmVlYjQyZWEyZWM4NDQ=
|
data/.gitignore
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/test/tmp/
|
9
|
+
/test/version_tmp/
|
10
|
+
/tmp/
|
11
|
+
|
12
|
+
## Specific to RubyMotion:
|
13
|
+
.dat*
|
14
|
+
.repl_history
|
15
|
+
build/
|
16
|
+
|
17
|
+
## Documentation cache and generated files:
|
18
|
+
/.yardoc/
|
19
|
+
/_yardoc/
|
20
|
+
/doc/
|
21
|
+
/rdoc/
|
22
|
+
|
23
|
+
## Environment normalisation:
|
24
|
+
/.bundle/
|
25
|
+
/lib/bundler/man/
|
26
|
+
|
27
|
+
# for a library or gem, you might want to ignore these files since the code is
|
28
|
+
# intended to run in multiple environments; otherwise, check them in:
|
29
|
+
# Gemfile.lock
|
30
|
+
# .ruby-version
|
31
|
+
# .ruby-gemset
|
32
|
+
|
33
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
34
|
+
.rvmrc
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-1.9.3-p551
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
rspec-junklet (1.0.4)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
builder (3.2.2)
|
10
|
+
coderay (1.1.0)
|
11
|
+
cucumber (1.3.18)
|
12
|
+
builder (>= 2.1.2)
|
13
|
+
diff-lcs (>= 1.1.3)
|
14
|
+
gherkin (~> 2.12)
|
15
|
+
multi_json (>= 1.7.5, < 2.0)
|
16
|
+
multi_test (>= 0.1.1)
|
17
|
+
diff-lcs (1.2.5)
|
18
|
+
gherkin (2.12.2)
|
19
|
+
multi_json (~> 1.3)
|
20
|
+
method_source (0.8.2)
|
21
|
+
multi_json (1.10.1)
|
22
|
+
multi_test (0.1.1)
|
23
|
+
pry (0.10.1)
|
24
|
+
coderay (~> 1.1.0)
|
25
|
+
method_source (~> 0.8.1)
|
26
|
+
slop (~> 3.4)
|
27
|
+
rake (10.4.2)
|
28
|
+
rspec (2.99.0)
|
29
|
+
rspec-core (~> 2.99.0)
|
30
|
+
rspec-expectations (~> 2.99.0)
|
31
|
+
rspec-mocks (~> 2.99.0)
|
32
|
+
rspec-core (2.99.2)
|
33
|
+
rspec-expectations (2.99.2)
|
34
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
35
|
+
rspec-mocks (2.99.2)
|
36
|
+
slop (3.6.0)
|
37
|
+
|
38
|
+
PLATFORMS
|
39
|
+
ruby
|
40
|
+
|
41
|
+
DEPENDENCIES
|
42
|
+
bundler (~> 1.7)
|
43
|
+
cucumber
|
44
|
+
pry
|
45
|
+
rake (~> 10.0)
|
46
|
+
rspec (~> 2.0)
|
47
|
+
rspec-junklet!
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 CoverMyMeds
|
4
|
+
|
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:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
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 THE
|
21
|
+
SOFTWARE.
|
22
|
+
|
data/README.md
ADDED
@@ -0,0 +1,314 @@
|
|
1
|
+
# Junklet
|
2
|
+
|
3
|
+
Cache tiny chunks of unique junk data in RSpec with `junklet :name`; get handy
|
4
|
+
clumps of junk data at any time with `junk`. Size your junk with e.g. `junk 100`
|
5
|
+
or `junk 4`.
|
6
|
+
|
7
|
+
Junklet data is fixture data that:
|
8
|
+
|
9
|
+
* We essentially don't care about,
|
10
|
+
* But we might want to test for equality somewhere later,
|
11
|
+
* And we might need to be unique between runs in case a spec crashes and
|
12
|
+
SQLServer fails to clean up the test database
|
13
|
+
|
14
|
+
So,
|
15
|
+
|
16
|
+
* We want it to be easy to create junk data fields quickly and easily, and
|
17
|
+
* If equality fails we want to be led to the offending field by the error
|
18
|
+
message and not just the line number in the stack trace.
|
19
|
+
|
20
|
+
## Installation
|
21
|
+
|
22
|
+
Add this line to your application's Gemfile:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
gem 'rspec-junklet'
|
26
|
+
```
|
27
|
+
|
28
|
+
And then execute:
|
29
|
+
|
30
|
+
$ bundle
|
31
|
+
|
32
|
+
Or install it yourself as:
|
33
|
+
|
34
|
+
$ gem install rspec-junklet
|
35
|
+
|
36
|
+
# Usage
|
37
|
+
|
38
|
+
junklet adds two keywords to RSpec's DSL: `junklet`, which defines a `let`
|
39
|
+
statement containing junk data, and `junk`, which is a method that returns many
|
40
|
+
and varied types of junk data. The former is meant to be used as part of the DSL
|
41
|
+
to declare pieces of data to be junk, while the latter is intended to be used
|
42
|
+
anywhere inside RSpec to supply the junk data itself.
|
43
|
+
|
44
|
+
To illustrate, these statements are functionally identical:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
junklet :pigtruck
|
48
|
+
let(:pigtruck) { junk }
|
49
|
+
```
|
50
|
+
|
51
|
+
## Junklet
|
52
|
+
|
53
|
+
`junklet` declares a memoized variable containing random junk.
|
54
|
+
|
55
|
+
junklet :var [, :var_2 [...]] [, options_hash]
|
56
|
+
|
57
|
+
So, for example,
|
58
|
+
|
59
|
+
junklet :first_name
|
60
|
+
|
61
|
+
Creates a `let :first_name` with the value of
|
62
|
+
`first_name-774030d0f58d4f588c5edddbdc7f9580` (the hex number is a uuid without
|
63
|
+
hyphens and will change with each test _case_, not just each test run).
|
64
|
+
|
65
|
+
Currently the options hash only gives you control over the variable names appear
|
66
|
+
in the junk data, not the junk data itself. For example,
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
junklet :host_name, separator: '-'
|
70
|
+
```
|
71
|
+
|
72
|
+
Creates a `let :host_name`, but changes underscores to hyphens in the string
|
73
|
+
value, e.g. `host-name-774030d0f58d4f588c5edddbdc7f9580`. Useful specifically
|
74
|
+
for host names, which cannot have underscores in them.
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
junklet :a_a, :b_b, :c_c, separator: '.'
|
78
|
+
```
|
79
|
+
|
80
|
+
Does what it says on the tin: creates 3 items with string values of
|
81
|
+
`a.a.774...`, `b.b.1234...`, and `c.c.234abc...` respectively. I don't know why
|
82
|
+
you'd need this, but hey, if you do there it is.
|
83
|
+
|
84
|
+
## Junk
|
85
|
+
|
86
|
+
`junk` returns random junk, which can be finely tuned and fiddled with.
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
junk
|
90
|
+
junk (integer|symbol|enumerable|proc) [options]
|
91
|
+
```
|
92
|
+
|
93
|
+
By default, just calling `junk` from inside a spec or let block returns a random
|
94
|
+
hex string 32 bytes long.
|
95
|
+
|
96
|
+
### integer
|
97
|
+
|
98
|
+
Give junk an integer argument and it will return that many hexadecimal digits of
|
99
|
+
junk data. Note that this is HALF the number of digits returned if you were to
|
100
|
+
call `SecureRandom.hex(n)`, because `hex(n)` returns n _bytes_, each of which
|
101
|
+
requires two hex digits to represent. Since we're more concerned about specific
|
102
|
+
byte lengths, `junk(n)` gives you n digits, not n*2 digits representing n bytes.
|
103
|
+
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
junk 17 - return 17 bytes of junk data
|
107
|
+
```
|
108
|
+
|
109
|
+
### symbol
|
110
|
+
|
111
|
+
junk may be given a symbol denoting the type of data to be returned. Currently
|
112
|
+
`:int` and `:bool` are the only supported types. `junk :bool` merely returns
|
113
|
+
true or false; `junk :int` is much more complicated and interesting.
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
junk :bool # Boring. Well, 50% chance of boring.
|
117
|
+
```
|
118
|
+
|
119
|
+
`junk :int` is the most complicated and/or interesting type of junk. It returns
|
120
|
+
a random decimal number, and it has the most options such as `size` (number of
|
121
|
+
digits), and `min` and `max` (which sort of do what you'd expect).
|
122
|
+
|
123
|
+
By default, `junk :int` returns a random number from 0 to the largest possible
|
124
|
+
`Fixnum`, which is 2**62-1.
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
junk :int # return a random integer from 0 to 2**62-1 (maximum size of
|
128
|
+
a Fixnum)
|
129
|
+
```
|
130
|
+
|
131
|
+
`size`, `min` and `max` control the size and bounds of the random number.
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
junk :int, size: 3 # returns a 3-digit decimal from 100 to 999.
|
135
|
+
junk :int, max: 10 # returns a random number from 0 to 10.
|
136
|
+
junk :int, min: 100 # returns a random number from 100 to 2**62-1.
|
137
|
+
```
|
138
|
+
|
139
|
+
Note: You can mix size with min or max, but they can only be used to further
|
140
|
+
restrict the range, not expand it, because that would change the size
|
141
|
+
constraint. So these examples work the way you'd expect:
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
junk :int, size: 4, min: 2000 # random number 2000-9999
|
145
|
+
junk :int, size: 4, max: 2000 # random number 1000-2000
|
146
|
+
```
|
147
|
+
|
148
|
+
But in these examples, `min` and `max` have no effect:
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
junk :int, size: 2, min: 0 # nope, still gonna get 10-99
|
152
|
+
junk :int, size: 2, max: 200 # nope, still gonna get 10-99
|
153
|
+
```
|
154
|
+
|
155
|
+
Technically, you CAN use BOTH `min` and `max` with `size` to constrain both
|
156
|
+
bounds of the number, but this effectively makes the `size` option redundant. It
|
157
|
+
will work correctly, but if you remove the size constraint you'll still get the
|
158
|
+
same exact range:
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
# Don't do this - size argument is redundant
|
162
|
+
junk :int, size: 3, min: 125, max: 440 # 125-440. size is now redundant.
|
163
|
+
```
|
164
|
+
|
165
|
+
### Array / Enumerable
|
166
|
+
|
167
|
+
If you give junk an `Array`, `Range`, or any other object that implements
|
168
|
+
`Enumerable`, it will select an element at random from the collection.
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
junk [1,3,5,7,9] # pick a 1-digit odd number
|
172
|
+
junk (1..5).map {|x| x*2-1 } # pick a 1-digit odd number while trying way too hard
|
173
|
+
junk (1..9).step(2) # pick a 1-digit odd number, but now I'm just showing off
|
174
|
+
```
|
175
|
+
|
176
|
+
*IMPORTANT CAVEAT*: the Enumerable forms all use `.to_a.sample` to get the
|
177
|
+
random value, and `.to_a` will cheerfully exhaust all the memory Ruby has if you
|
178
|
+
use it on a sufficiently large array.
|
179
|
+
|
180
|
+
*LESS-IMPORTANT CAVEAT*: Technically anything that can be converted to an array
|
181
|
+
and then sampled can go through here, so `words.split` would do what you want,
|
182
|
+
but remember that hashes get turned into an array of _pairs_, so expect this
|
183
|
+
weirdness if you ask for it:
|
184
|
+
|
185
|
+
```ruby
|
186
|
+
junk({a: 42, b: 13}) # either [:a, 42] or [:b, 13]
|
187
|
+
```
|
188
|
+
|
189
|
+
### Proc
|
190
|
+
|
191
|
+
When all else fails, it's time to haul out the lambdas, amirite? The first
|
192
|
+
argument ot `junk` can be a proc that yields the desired random value. Let's get
|
193
|
+
those odd numbers again:
|
194
|
+
|
195
|
+
```ruby
|
196
|
+
junk ->{ rand(5)*2 + 1 } # 1-digit odd number
|
197
|
+
```
|
198
|
+
|
199
|
+
### Other Options
|
200
|
+
|
201
|
+
### Exclude
|
202
|
+
|
203
|
+
Besides the options that `:int` will take, all of the types will accept an
|
204
|
+
`exclude` argument. This is useful if you want to generate more than one piece
|
205
|
+
of junk data and ensure that they are different. The exclude option can be given
|
206
|
+
a single element, an array, or an enumerable, and if all that fails you can give
|
207
|
+
it a proc that accepts the generated value and returns true if the value should
|
208
|
+
be excluded. Let's use all these excludes to generate odd numbers again:
|
209
|
+
|
210
|
+
```ruby
|
211
|
+
junk :int, min: 1, max: 3, exclude: 2 # stupid, but it works
|
212
|
+
junk (1..9), exclude: [2,4,6,8]
|
213
|
+
junk (1..9), exclude: (2..8) # okay, only returns 1 or 9 but hey,
|
214
|
+
# they're both odd
|
215
|
+
junk :int, exclude: ->(x) { x % 2 == 0 } # reject even numbers
|
216
|
+
```
|
217
|
+
|
218
|
+
But again, the real advantage is being able to avoid collisions:
|
219
|
+
|
220
|
+
```ruby
|
221
|
+
let(:id1) { junk (0..9) }
|
222
|
+
let(:id2) { junk (0..9), exclude: id1 }
|
223
|
+
let(:id3) { junk (0..9), exclude: [id1, id2] }
|
224
|
+
|
225
|
+
let(:coinflip) { junk :bool }
|
226
|
+
let(:otherside) { junk :bool, exclude: coinflip } # Look I never said
|
227
|
+
# all of these were great ideas, I'm just saying you can DO them.
|
228
|
+
```
|
229
|
+
|
230
|
+
*VERY IMPORTANT CAVEAT* If you exclude all of the possibilities from the random
|
231
|
+
key space, junk will cheerfully go into an infinite loop.
|
232
|
+
|
233
|
+
### Format
|
234
|
+
|
235
|
+
Formats are here, but need documentating! For now: `format: :int` will cast your
|
236
|
+
junk to an integer by calling `.to_i` on it. Other formats include:
|
237
|
+
|
238
|
+
* `format: :int` calls `.to_i` on the junk before returning it
|
239
|
+
* `format: :string` calls `.to_s` on the junk
|
240
|
+
* `format: "%s"` (or any other string) calls sprintf on the junk with the
|
241
|
+
string as the format string
|
242
|
+
* `format: SomeClass` passes the junk to `SomeClass.new`, returning an instance
|
243
|
+
of `SomeClass`. *Note:* If you plan on combining this with `exclude`, make
|
244
|
+
sure your class implements the `==` operator.
|
245
|
+
* `format: ->(x) { ... }` passes the junk to your Proc
|
246
|
+
|
247
|
+
# TODO
|
248
|
+
|
249
|
+
* Allow all args to junk to be passed to junklet. Use explicit `type` option to
|
250
|
+
specify the type. E.g. `junklet :foo, :bar, :baz, type: :int, max: 14,
|
251
|
+
exclude: [:qaz, :qux]`. _(Do we want to allow a flag for mutually exclusive?)_
|
252
|
+
|
253
|
+
# Background
|
254
|
+
|
255
|
+
At CoverMyMeds we have a legacy impingement that prevents us sometimes from
|
256
|
+
clearing out data from previous test runs. As a result we often have required
|
257
|
+
fields in tests that must be unique but are tested elsewhere, so we don't really
|
258
|
+
care about them in the current test run. For the current test we just want to
|
259
|
+
stub out that field with something unique but we also want to communicate to the
|
260
|
+
developer that the contents of the field are not what we currently care about.
|
261
|
+
|
262
|
+
Currently we do this with `SecureRandom.uuid`, so we'll see code like
|
263
|
+
this frequently in RSpec:
|
264
|
+
|
265
|
+
```ruby
|
266
|
+
let(:first_name) { SecureRandom.uuid }
|
267
|
+
let(:last_name) { SecureRandom.uuid }
|
268
|
+
let(:address) { SecureRandom.uuid }
|
269
|
+
let(:city) { SecureRandom.uuid }
|
270
|
+
let(:state) { SecureRandom.uuid }
|
271
|
+
let(:phone) { SecureRandom.uuid }
|
272
|
+
```
|
273
|
+
|
274
|
+
...etc. Later in the spec we'll often test against those stubs, e.g. with
|
275
|
+
`expect(user.first_name).to eq(first_name)` but this idiom expresses that we
|
276
|
+
only care about the equality, not the actual contents.
|
277
|
+
|
278
|
+
Junklet seeks to improve the readability and conciseness of this intention. One
|
279
|
+
thing that bugs me about the above approach is that if a weird regression bug
|
280
|
+
appears and an unimportant field is the source of a crash. So with Junklet I
|
281
|
+
also wanted to add the ability to call out the offending field by name. In
|
282
|
+
theory we could just write `let(:first_name) { 'first_name-' + SecureRandom.uuid
|
283
|
+
}` but in practice that creates duplication in the code and muddies the original
|
284
|
+
idiom of "uncared-about" data.
|
285
|
+
|
286
|
+
Enter Junklet:
|
287
|
+
|
288
|
+
```ruby
|
289
|
+
junklet :first_name
|
290
|
+
junklet :last_name
|
291
|
+
junklet :address
|
292
|
+
junklet :city
|
293
|
+
junklet :state
|
294
|
+
junklet :phone
|
295
|
+
```
|
296
|
+
|
297
|
+
Or, if you don't want the junklets to sprawl vertically,
|
298
|
+
|
299
|
+
```ruby
|
300
|
+
junklet :first_name, :last_name, :address, :city, :state, :phone
|
301
|
+
```
|
302
|
+
|
303
|
+
This will have the same effect as calling `let` on the named fields and setting
|
304
|
+
the fieldname and a 32-byte hex string (a uuid with hyphens removed) to be the
|
305
|
+
memoized value.
|
306
|
+
|
307
|
+
## Contributing
|
308
|
+
|
309
|
+
1. Fork it ( https://github.com/[my-github-username]/junklet/fork )
|
310
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
311
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
312
|
+
4. Write specs to document how your change is to be used
|
313
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
314
|
+
6. Create a new Pull Request
|
data/lib/junklet/junk.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
module Junklet
|
2
|
+
module Junk
|
3
|
+
def junk(*args)
|
4
|
+
# TODO: It's long past time to extract this....
|
5
|
+
|
6
|
+
# args.first can be
|
7
|
+
# - an integer indicating the size of the hex string to return
|
8
|
+
# - a symbol denoting the base type, e.g. :int
|
9
|
+
# - an array to sample from
|
10
|
+
# - a range or Enumerable to sample from. WARNING: will call
|
11
|
+
# .to_a on it first, which might be expensive
|
12
|
+
# - a generator Proc which, when called, will generate the
|
13
|
+
# value to use.
|
14
|
+
#
|
15
|
+
# args.rest is a hash of options:
|
16
|
+
# - sequence: Proc or Array of values to choose from.
|
17
|
+
# - exclude: value, array of values, or proc to exclude. If a
|
18
|
+
# Proc is given, it takes the value generated and returns
|
19
|
+
# true if the value should be excluded.
|
20
|
+
#
|
21
|
+
# - for int:
|
22
|
+
# - min: minimum number to return. Default: 0
|
23
|
+
# - max: upper limit of range
|
24
|
+
# - exclude: number, array of numbers, or proc to
|
25
|
+
# exclude. If Proc is provided, tests the number against
|
26
|
+
# the Proc an excludes it if the Proc returns true. This
|
27
|
+
# is implemented except for the proc.
|
28
|
+
|
29
|
+
# FIXME: Raise Argument error unless *args.size is 0-2
|
30
|
+
# FIXME: If arg 1 is a hash, it's the options hash, raise
|
31
|
+
# ArgumentError unless args.size == 1
|
32
|
+
# FIXME: If arg 2 present, Raise Argument error unless it's a
|
33
|
+
# hash.
|
34
|
+
# FIXME: Figure out what our valid options are and parse them;
|
35
|
+
# raise errors if present.
|
36
|
+
|
37
|
+
junk_types = [Symbol, Array, Enumerable, Proc]
|
38
|
+
if args.size > 0 && junk_types.any? {|klass| args.first.is_a?(klass) }
|
39
|
+
type = args.shift
|
40
|
+
opts = args.last || {}
|
41
|
+
|
42
|
+
excluder = if opts[:exclude]
|
43
|
+
if opts[:exclude].is_a?(Proc)
|
44
|
+
opts[:exclude]
|
45
|
+
else
|
46
|
+
->(x) { Array(opts[:exclude]).include?(x) }
|
47
|
+
end
|
48
|
+
else
|
49
|
+
->(x) { false }
|
50
|
+
end
|
51
|
+
|
52
|
+
formatter = case opts[:format]
|
53
|
+
when :string
|
54
|
+
->(x) { x.to_s }
|
55
|
+
when :int
|
56
|
+
->(x) { x.to_i }
|
57
|
+
when String
|
58
|
+
->(x) { sprintf(opts[:format], x) }
|
59
|
+
when Class
|
60
|
+
->(x) { opts[:format].new(x) }
|
61
|
+
when Proc
|
62
|
+
opts[:format]
|
63
|
+
else
|
64
|
+
->(x) { x }
|
65
|
+
end
|
66
|
+
|
67
|
+
# TODO: Refactor me. Seriously, this is a functional
|
68
|
+
# programming version of the strategy pattern. Wouldn't it
|
69
|
+
# be neat if we had some kind of object-oriented language
|
70
|
+
# available here?
|
71
|
+
case type
|
72
|
+
when :int
|
73
|
+
# min,max cooperate with size to further constrain it. So
|
74
|
+
# size: 2, min: 30 would be min 30, max 99.
|
75
|
+
if opts[:size]
|
76
|
+
sized_min = 10**(opts[:size]-1)
|
77
|
+
sized_max = 10**opts[:size]-1
|
78
|
+
end
|
79
|
+
explicit_min = opts[:min] || 0
|
80
|
+
explicit_max = (opts[:max] || 2**62-2) + 1
|
81
|
+
|
82
|
+
if sized_min
|
83
|
+
min = [sized_min, explicit_min].max
|
84
|
+
max = [sized_max, explicit_max].min
|
85
|
+
else
|
86
|
+
min = sized_min || explicit_min
|
87
|
+
max = sized_max || explicit_max
|
88
|
+
end
|
89
|
+
|
90
|
+
min,max = max,min if min>max
|
91
|
+
|
92
|
+
generator = -> { rand(max-min) + min }
|
93
|
+
when :bool
|
94
|
+
generator = -> { [true, false].sample }
|
95
|
+
when Array, Enumerable
|
96
|
+
generator = -> { type.to_a.sample }
|
97
|
+
when Proc
|
98
|
+
generator = type
|
99
|
+
else
|
100
|
+
raise "Unrecognized junk type: '#{type}'"
|
101
|
+
end
|
102
|
+
|
103
|
+
begin
|
104
|
+
val = formatter.call(generator.call)
|
105
|
+
end while excluder.call(val)
|
106
|
+
val
|
107
|
+
else
|
108
|
+
size = args.first.is_a?(Numeric) ? args.first : 32
|
109
|
+
# hex returns size*2 digits, because it returns a 0..255 byte
|
110
|
+
# as a hex pair. But when we want junt, we want *bytes* of
|
111
|
+
# junk. Get (size+1)/2 chars, which will be correct for even
|
112
|
+
# sizes and 1 char too many for odds, so trim off with
|
113
|
+
# [0...size] (note three .'s to trim off final char)
|
114
|
+
SecureRandom.hex((size+1)/2)[0...size]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Junklet
|
2
|
+
module Junklet
|
3
|
+
def junklet(*args)
|
4
|
+
# TODO: figure out how to use this to wrap junk in junklet,
|
5
|
+
# so that junklet can basically have all the same options as
|
6
|
+
# junk does. E.g. junklet :ddid, :pcn, :group, type: :int,
|
7
|
+
# min: 100000, max: 999999, etc, and you'd get back 3
|
8
|
+
# junklets of 6-digit numbers.
|
9
|
+
opts = args.size > 1 && !args.last.is_a?(Symbol) && args.pop || {}
|
10
|
+
|
11
|
+
names = args.map(&:to_s)
|
12
|
+
|
13
|
+
separator = opts[:separator] || '_'
|
14
|
+
names = names.map {|name| name.gsub(/_/, separator)}
|
15
|
+
|
16
|
+
args.zip(names).each do |arg, name|
|
17
|
+
make_junklet arg, name, separator, junk
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def make_junklet(let_name, name, separator, junk_data)
|
22
|
+
let(let_name) { "#{name}#{separator}#{junk_data}" }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/junklet.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require "junklet/version"
|
2
|
+
require "junklet/junk"
|
3
|
+
require "junklet/junklet"
|
4
|
+
|
5
|
+
RSpec.configure do |config|
|
6
|
+
config.extend(Junklet::Junklet)
|
7
|
+
config.extend(Junklet::Junk) # when metaprogramming cases, you may need junk in ExampleGroups
|
8
|
+
config.include(Junklet::Junk)
|
9
|
+
end
|
data/lib/line.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
class Line < String
|
2
|
+
def initialize(line="")
|
3
|
+
super
|
4
|
+
end
|
5
|
+
|
6
|
+
def indent
|
7
|
+
' ' * (size - lstrip.size)
|
8
|
+
end
|
9
|
+
|
10
|
+
def let?
|
11
|
+
match(/^\s*let\s*\(/) && !junklet?
|
12
|
+
end
|
13
|
+
|
14
|
+
def junklet?
|
15
|
+
already_junklet? || secure_random?
|
16
|
+
end
|
17
|
+
|
18
|
+
def already_junklet?
|
19
|
+
match(/^\s*junklet\b/)
|
20
|
+
end
|
21
|
+
|
22
|
+
def secure_random?
|
23
|
+
match(/^\s*(let)\s*\(?([^)]*)\)\s*{\s*SecureRandom.(uuid|hex)\s*}/)
|
24
|
+
end
|
25
|
+
|
26
|
+
def code?
|
27
|
+
empty? || (!let? && !junklet?)
|
28
|
+
end
|
29
|
+
|
30
|
+
def names
|
31
|
+
return nil unless let? || junklet?
|
32
|
+
match(/^\s*(let|junklet)\s*\(?([^)]*)\)?/) \
|
33
|
+
.captures[1..-1] \
|
34
|
+
.join('') \
|
35
|
+
.split(/,/) \
|
36
|
+
.map(&:strip)
|
37
|
+
end
|
38
|
+
|
39
|
+
def convert
|
40
|
+
return nil unless junklet?
|
41
|
+
return self if already_junklet?
|
42
|
+
Line.new("#{indent}junklet #{names.first}")
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'junklet/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "rspec-junklet"
|
8
|
+
spec.version = Junklet::VERSION
|
9
|
+
spec.authors = ["David Brady"]
|
10
|
+
spec.email = ["dbrady@shinybit.com"]
|
11
|
+
spec.summary = "Easily create junk data for specs"
|
12
|
+
spec.description = "Works like let for rspec, but creates unique random junk data"
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
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.7"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
spec.add_development_dependency "rspec", "~> 2.0"
|
24
|
+
spec.add_development_dependency "cucumber"
|
25
|
+
spec.add_development_dependency "pry"
|
26
|
+
end
|