rspec-junklet 1.1.0

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 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
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in junklet.gemspec
4
+ gemspec
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
@@ -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
@@ -0,0 +1,3 @@
1
+ module Junklet
2
+ VERSION = "1.1.0"
3
+ 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
@@ -0,0 +1,6 @@
1
+ let(:name) { "Bob" }
2
+ let(:city) { "Faketown" }
3
+ let(:extra) { true }
4
+ let(:pants) { ON_FIRE }
5
+
6
+ junklet :address, :state, :zip
@@ -0,0 +1,7 @@
1
+ let(:name) { "Bob" }
2
+ junklet :address
3
+ let(:city) { "Faketown" }
4
+ junklet :state
5
+ junklet :zip
6
+ let(:extra) { true }
7
+ let(:pants) { ON_FIRE }