crimp 0.2.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/.travis.yml +3 -1
- data/LICENSE.txt +17 -18
- data/README.md +157 -15
- data/Rakefile +6 -2
- data/crimp.gemspec +13 -24
- data/lib/crimp.rb +41 -63
- data/spec/acceptance_data.yml +66 -0
- data/spec/acceptance_spec.rb +23 -0
- data/spec/crimp_spec.rb +295 -95
- data/spec/spec_helper.rb +0 -1
- metadata +14 -99
- data/Guardfile +0 -6
- data/lib/crimp/version.rb +0 -3
- data/spec/consistency_spec.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c137825335bbd1636911bede1f6acba9dc001070c68cce11aa26d7bb1e79f120
|
4
|
+
data.tar.gz: 610febce9965c5c7f2efe2aea310613f7e854b9de8de3ae1263acf525f12f78a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87a85aedb707739ea28220183e96dbbfb51ed84443314a5cb2459c36f9ea0dd2d1d4e1ddd6a61e6ec43730414d73a021961e3861f1aca4c9e13fb7d8025ed6d3
|
7
|
+
data.tar.gz: 64edcb40a960ad815a0b4c2006d89e091f27b4a1102ad622be001dcae0b324942493d6737bd7b7205945253710c94e1e977dc6699e9ef354cbd44046c15ae969
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.5.1
|
data/.travis.yml
CHANGED
data/LICENSE.txt
CHANGED
@@ -1,22 +1,21 @@
|
|
1
|
-
|
1
|
+
The MIT License
|
2
2
|
|
3
|
-
|
3
|
+
Copyright (c) 2014-2018 BBC News https://www.bbc.co.uk/news
|
4
4
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
the following conditions:
|
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:
|
12
11
|
|
13
|
-
The above copyright notice and this permission notice shall be
|
14
|
-
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
15
14
|
|
16
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
OF
|
22
|
-
|
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
|
21
|
+
THE SOFTWARE.
|
data/README.md
CHANGED
@@ -3,45 +3,187 @@
|
|
3
3
|
[![Build Status](https://travis-ci.org/BBC-News/crimp.png?branch=master)](https://travis-ci.org/BBC-News/crimp)
|
4
4
|
[![Gem Version](https://badge.fury.io/rb/crimp.png)](http://badge.fury.io/rb/crimp)
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
![mighty-boosh-four-way-crimp-o](https://f.cloud.github.com/assets/180050/2148112/b44fd6fa-93de-11e3-9f9a-ad941f069b5c.gif)
|
9
|
-
|
10
|
-
Shamelessly copied from [this Stack Overflow
|
11
|
-
answer](http://stackoverflow.com/a/6462589/3243663).
|
6
|
+
Creates an MD5 hash from simple data structures made of numbers, strings, booleans, nil, arrays or hashes.
|
12
7
|
|
13
8
|
## Installation
|
14
9
|
|
15
10
|
Add this line to your application's Gemfile:
|
16
11
|
|
17
|
-
|
12
|
+
```ruby
|
13
|
+
gem 'crimp'
|
14
|
+
|
15
|
+
```
|
18
16
|
|
19
17
|
And then execute:
|
20
18
|
|
21
|
-
|
19
|
+
```shell
|
20
|
+
$ bundle
|
21
|
+
|
22
|
+
```
|
22
23
|
|
23
24
|
Or install it yourself as:
|
24
25
|
|
25
|
-
|
26
|
+
```shell
|
27
|
+
$ gem install crimp
|
28
|
+
```
|
26
29
|
|
27
30
|
## Usage
|
28
31
|
|
29
|
-
```
|
32
|
+
```ruby
|
30
33
|
require 'crimp'
|
31
34
|
|
32
|
-
Crimp.
|
35
|
+
Crimp.signature({ a: { b: 1 } })
|
36
|
+
=> "ac13c15d07e5fa3992fc6b15113db900"
|
37
|
+
```
|
38
|
+
|
39
|
+
## Multiplatform design
|
40
|
+
|
41
|
+
At the BBC we use Crimp to build keys for database and cache entries.
|
42
|
+
|
43
|
+
If you want to build a similar library with your language of choice you should be able to follow the simple specifications defined in `spec/crimp_spec.rb`. Using these simple rules you will produce a string ready to be MD5 signed.
|
44
|
+
|
45
|
+
Once you get your string, is very important to be sure that you can produce the same key in any language. MD5 is your friend:
|
46
|
+
|
47
|
+
### Ruby
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
irb(main):001:0> require 'digest'
|
51
|
+
=> true
|
52
|
+
irb(main):002:0> Digest::MD5.hexdigest('abc')
|
53
|
+
=> "900150983cd24fb0d6963f7d28e17f72"
|
54
|
+
```
|
55
|
+
|
56
|
+
### Lua
|
57
|
+
|
58
|
+
```lua
|
59
|
+
Lua 5.3.5 Copyright (C) 1994-2018 Lua.org, PUC-Rio
|
60
|
+
> md5 = require 'md5'
|
61
|
+
> md5.sumhexa('abc')
|
62
|
+
900150983cd24fb0d6963f7d28e17f72
|
63
|
+
```
|
33
64
|
|
34
|
-
|
65
|
+
### Elixir
|
35
66
|
|
36
|
-
|
67
|
+
``` elixir
|
68
|
+
Erlang/OTP 21 [erts-10.0.4] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] [dtrace]
|
69
|
+
Interactive Elixir (1.7.2) - press Ctrl+C to exit (type h() ENTER for help)
|
70
|
+
iex(1)> :crypto.hash(:md5 , "abc") |> Base.encode16() |> String.downcase
|
71
|
+
"900150983cd24fb0d6963f7d28e17f72"
|
72
|
+
```
|
37
73
|
|
38
|
-
|
74
|
+
### Node.js
|
39
75
|
|
76
|
+
``` javascript
|
77
|
+
> var crypto = require('crypto');
|
78
|
+
undefined
|
79
|
+
> crypto.createHash('md5').update('abc').digest('hex');
|
80
|
+
'900150983cd24fb0d6963f7d28e17f72'
|
40
81
|
```
|
41
82
|
|
83
|
+
## Fine prints
|
84
|
+
|
85
|
+
### Symbols
|
86
|
+
|
87
|
+
To make Crimp signatures reproducible in any platform we decided to ignore Ruby symbols and treat them as strings, so:
|
88
|
+
|
89
|
+
``` ruby
|
90
|
+
Crimp.signature(:a) == Crimp.Signature('a')
|
91
|
+
```
|
92
|
+
|
93
|
+
### Sets
|
94
|
+
|
95
|
+
Also Sets get transformed to Arrays:
|
96
|
+
|
97
|
+
``` ruby
|
98
|
+
Crimp.signature(Set.new(['a', 'b'])) == Crimp.signature(['a', 'b'])
|
99
|
+
```
|
100
|
+
|
101
|
+
### Sorting of collections
|
102
|
+
|
103
|
+
Crimp signatures are generated against sorted collections.
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
Crimp.signature([1, 2]) == Crimp.signature([2, 1])
|
107
|
+
Crimp.signature({'b' => 2, 'a' => 1}) == Crimp.signature({'a' => 1, 'b' => 2})
|
108
|
+
```
|
109
|
+
|
110
|
+
Crimp also sorts nested collections.
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
Crimp.signature([1, [3, 2], 4]) == Crimp.signature([4, [2, 3], 1])
|
114
|
+
Crimp.signature({'b' => {'d' => 2,'c' => 1}, 'a' => [3, 1, 2]}) == Crimp.signature({'a' => [1, 2, 3], 'b' => { 'c' => 1, 'd' => 2 }})
|
115
|
+
```
|
116
|
+
|
117
|
+
### Custom objects
|
118
|
+
|
119
|
+
Crimp will complain if you try to get a signature from an instance of some custom object:
|
120
|
+
|
121
|
+
``` ruby
|
122
|
+
Crimp.signature(Object.new)
|
123
|
+
=> TypeError: Expected a (String|Number|Boolean|Nil|Hash|Array), Got Object
|
124
|
+
```
|
125
|
+
It is your responsibility to pass a compatible representation of your object to Crimp.
|
126
|
+
|
127
|
+
## Implementation details
|
128
|
+
|
129
|
+
Under the hood Crimp annotates the passed data structure to a nested array of primitives (strings, numbers, booleans, nils, etc.) and a single byte to indicate the type of the primitive:
|
130
|
+
|
131
|
+
| Type | Byte |
|
132
|
+
| :-: | :-: |
|
133
|
+
| String | `S` |
|
134
|
+
| Number | `N` |
|
135
|
+
| Boolean | `B` |
|
136
|
+
| nil | `_` |
|
137
|
+
| Array | `A` |
|
138
|
+
| Hash | `H` |
|
139
|
+
|
140
|
+
You can verify it using the `#annotate` method:
|
141
|
+
|
142
|
+
``` ruby
|
143
|
+
Crimp.annotate({ a: 1 })
|
144
|
+
=> [[[[[1, "N"], ["a", "S"]], "A"]], "H"]
|
145
|
+
```
|
146
|
+
Notice how Crimp marks the collection as Hash (`H`) and then transforms the tuple of key/values to an Array (`A`).
|
147
|
+
|
148
|
+
Here's an example with nested hashes:
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
Crimp.annotate({ a: { b: 'c' } })
|
152
|
+
=> [[[[["a", "S"], [[[[["b", "S"], ["c", "S"]], "A"]], "H"]], "A"]], "H"]
|
153
|
+
```
|
154
|
+
|
155
|
+
Before signing Crimp transforms the collection of nested array to a string.
|
156
|
+
|
157
|
+
```ruby
|
158
|
+
Crimp.notation({ a: { b: 'c' } })
|
159
|
+
=> "aSbScSAHAH"
|
160
|
+
```
|
161
|
+
|
162
|
+
Please note the Arrays and Hash keys are sorted before signing.
|
163
|
+
|
164
|
+
``` ruby
|
165
|
+
Crimp.notation([3, 1, 2])
|
166
|
+
=> "1N2N3NA"
|
167
|
+
```
|
168
|
+
|
169
|
+
key/value tuples get sorted as well.
|
170
|
+
|
171
|
+
``` ruby
|
172
|
+
Crimp.notation({ a: 1 })
|
173
|
+
=> "1NaSAH"
|
174
|
+
```
|
175
|
+
|
176
|
+
## Changelog
|
177
|
+
|
178
|
+
| Version | Changes |
|
179
|
+
|---------|----------------------------------------------------------------------------|
|
180
|
+
|`v0.x` | Original version of Crimp. |
|
181
|
+
|`v0.2.0` | Crimp compatibility with Ruby >= 2.4, use this for legacy projects. |
|
182
|
+
|`v1.0.0` | Includes **breaking changes** and returns different signatures from `v0.2` |
|
183
|
+
|
42
184
|
## Contributing
|
43
185
|
|
44
|
-
1. Fork it ( http://github.com
|
186
|
+
1. Fork it ( http://github.com/BBC-News/crimp/fork )
|
45
187
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
46
188
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
47
189
|
4. Push to the branch (`git push origin my-new-feature`)
|
data/Rakefile
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), 'lib')
|
2
2
|
|
3
|
+
require 'rspec/core/rake_task'
|
3
4
|
require 'bundler/gem_tasks'
|
4
|
-
require 'rake/rspec'
|
5
5
|
|
6
|
-
|
6
|
+
RSpec::Core::RakeTask.new :specs do |task|
|
7
|
+
task.pattern = Dir['spec/**/*_spec.rb']
|
8
|
+
end
|
9
|
+
|
10
|
+
task default: [:specs]
|
data/crimp.gemspec
CHANGED
@@ -1,35 +1,24 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
lib = File.expand_path('../lib', __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'crimp/version'
|
5
4
|
|
6
5
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
8
|
-
spec.version =
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
11
|
-
spec.summary =
|
12
|
-
spec.description =
|
13
|
-
|
14
|
-
|
15
|
-
All credit should go to http://stackoverflow.com/users/394282/luke
|
16
|
-
EOS
|
17
|
-
spec.homepage = ""
|
18
|
-
spec.license = "MIT"
|
6
|
+
spec.name = 'crimp'
|
7
|
+
spec.version = '1.0.0'
|
8
|
+
spec.authors = ['BBC News']
|
9
|
+
spec.email = ['D&ENewsFrameworksTeam@bbc.co.uk']
|
10
|
+
spec.summary = 'Creates an MD5 hash from simple data structures.'
|
11
|
+
spec.description = 'Platform agnostic MD5 hash from simple data structures made of numbers, strings, booleans, nil, arrays or hashes.'
|
12
|
+
spec.homepage = 'https://www.bbc.co.uk/news'
|
13
|
+
spec.license = 'MIT'
|
19
14
|
|
20
15
|
spec.files = `git ls-files -z`.split("\x0")
|
21
16
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
22
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
23
|
-
spec.require_paths = [
|
18
|
+
spec.require_paths = ['lib']
|
24
19
|
|
25
|
-
spec.add_development_dependency
|
26
|
-
spec.add_development_dependency
|
27
|
-
spec.add_development_dependency
|
28
|
-
spec.
|
29
|
-
spec.add_development_dependency "rspec-nc"
|
30
|
-
spec.add_development_dependency "guard"
|
31
|
-
spec.add_development_dependency "guard-rspec"
|
32
|
-
spec.add_development_dependency "pry"
|
33
|
-
spec.add_development_dependency "pry-remote"
|
34
|
-
spec.add_development_dependency "pry-nav"
|
20
|
+
spec.add_development_dependency 'bundler'
|
21
|
+
spec.add_development_dependency 'rake'
|
22
|
+
spec.add_development_dependency 'rspec'
|
23
|
+
spec.add_dependency 'deepsort'
|
35
24
|
end
|
data/lib/crimp.rb
CHANGED
@@ -1,74 +1,52 @@
|
|
1
|
-
|
2
|
-
require 'digest'
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
self >= 4611686018427387904
|
8
|
-
end
|
9
|
-
end
|
3
|
+
require 'digest/md5'
|
4
|
+
require 'set'
|
5
|
+
require 'deepsort'
|
10
6
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
def self.stringify(obj)
|
17
|
-
convert(obj).tap { |o| return o.class == String ? o : to_string(o) }
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def self.convert(obj)
|
23
|
-
case obj
|
24
|
-
when Array
|
25
|
-
parse_array obj
|
26
|
-
when Hash
|
27
|
-
parse_hash obj
|
28
|
-
when String
|
29
|
-
obj
|
30
|
-
else
|
31
|
-
to_string obj
|
7
|
+
class Crimp
|
8
|
+
class << self
|
9
|
+
def signature(obj)
|
10
|
+
Digest::MD5.hexdigest(notation(obj))
|
32
11
|
end
|
33
|
-
end
|
34
12
|
|
35
|
-
|
36
|
-
|
37
|
-
hash.each { |k, v| a << pair_to_string(k, v) }
|
13
|
+
def notation(obj)
|
14
|
+
annotate(obj).flatten.join
|
38
15
|
end
|
39
|
-
end
|
40
16
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
17
|
+
def annotate(obj)
|
18
|
+
obj = coerce(obj)
|
19
|
+
|
20
|
+
case obj
|
21
|
+
when String
|
22
|
+
[obj, 'S']
|
23
|
+
when Numeric
|
24
|
+
[obj, 'N']
|
25
|
+
when TrueClass, FalseClass
|
26
|
+
[obj, 'B']
|
27
|
+
when NilClass
|
28
|
+
[nil, '_']
|
29
|
+
when Array
|
30
|
+
[sort(obj), 'A']
|
31
|
+
when Hash
|
32
|
+
[sort(obj), 'H']
|
33
|
+
else
|
34
|
+
raise TypeError, "Expected a (String|Number|Boolean|Nil|Hash|Array), Got #{obj.class}."
|
35
|
+
end
|
36
|
+
end
|
48
37
|
|
49
|
-
|
50
|
-
stringify hash_to_array(hash)
|
51
|
-
end
|
38
|
+
private
|
52
39
|
|
53
|
-
|
54
|
-
|
55
|
-
|
40
|
+
def sort(coll)
|
41
|
+
coll.deep_sort_by { |obj| obj.to_s }.map { |obj| annotate(obj) }
|
42
|
+
end
|
56
43
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
# Say you have a huge number of stored keys and you migrate your app from 2.1 to >= 2.4
|
65
|
-
# this would cause a change of the signature for a subset of the keys which would be hard
|
66
|
-
# to debug especially for nested data structures.
|
67
|
-
#
|
68
|
-
def self.legacy_class(obj)
|
69
|
-
return obj.class unless obj.is_a?(Numeric)
|
70
|
-
return 'Float' if obj.is_a?(Float)
|
71
|
-
return 'Bignum' if obj.bignum?
|
72
|
-
'Fixnum'
|
44
|
+
def coerce(obj)
|
45
|
+
case obj
|
46
|
+
when Symbol then obj.to_s
|
47
|
+
when Set then obj.to_a
|
48
|
+
else obj
|
49
|
+
end
|
50
|
+
end
|
73
51
|
end
|
74
52
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
---
|
2
|
+
-
|
3
|
+
desc: verify String handling
|
4
|
+
json: abc
|
5
|
+
string: abcS
|
6
|
+
signature: c4449120506d97975c67be69719a78e2
|
7
|
+
-
|
8
|
+
desc: verify integers handling
|
9
|
+
json: 1
|
10
|
+
string: 1N
|
11
|
+
signature: 594170053719896a11eb08ee513813d5
|
12
|
+
-
|
13
|
+
desc: verify floats handling
|
14
|
+
json: 1.2
|
15
|
+
string: 1.2N
|
16
|
+
signature: f1ab6592886cd4b1b66ed55e73d9ab81
|
17
|
+
-
|
18
|
+
desc: verify Array handling
|
19
|
+
json: [1, "a", 3]
|
20
|
+
string: 1N3NaSA
|
21
|
+
signature: cd1c43797d488d0f6c0d71537c64d30b
|
22
|
+
-
|
23
|
+
desc: verify Array sorting
|
24
|
+
json: [3, null, 1, "1"]
|
25
|
+
string: _1N1S3NA
|
26
|
+
signature: 518e7bb17674f6acbb296845862a152d
|
27
|
+
-
|
28
|
+
desc: verify Array sorting with capital letters
|
29
|
+
json: ["a", "A", "b", "B"]
|
30
|
+
string: ASBSaSbSA
|
31
|
+
signature: f6692ab4bc94b35e61ec15c2d1891734
|
32
|
+
-
|
33
|
+
desc: verify nested Arrays
|
34
|
+
json: ["a", 1, ["b", "2"]]
|
35
|
+
string: 1N2SbSAaSA
|
36
|
+
signature: 3aaa58da4841eaeb41d3726d2c6fd875
|
37
|
+
-
|
38
|
+
desc: verify nested Arrays
|
39
|
+
json: [["b", "2"], "a", 1]
|
40
|
+
string: 1N2SbSAaSA
|
41
|
+
signature: 3aaa58da4841eaeb41d3726d2c6fd875
|
42
|
+
-
|
43
|
+
desc: verify hash like data structures
|
44
|
+
json: {"a": 1}
|
45
|
+
string: 1NaSAH
|
46
|
+
signature: 8cb44d69badda0f34b0bab6bb3e7fdbf
|
47
|
+
-
|
48
|
+
desc: verify nested hash
|
49
|
+
json: {"a": {"c": null, "2": 2 }}
|
50
|
+
string: aS2S2NA_cSAHAH
|
51
|
+
signature: bff3538075e4007c7679a7ba0d0a5f30
|
52
|
+
-
|
53
|
+
desc: verify null values
|
54
|
+
json: null
|
55
|
+
string: _
|
56
|
+
signature: b14a7b8059d9c055954c92674ce60032
|
57
|
+
-
|
58
|
+
desc: verify true boolean values
|
59
|
+
json: true
|
60
|
+
string: trueB
|
61
|
+
signature: 6413cfeb7a89f7e0a8872f82b919c0d9
|
62
|
+
-
|
63
|
+
desc: verify false boolean values
|
64
|
+
json: false
|
65
|
+
string: falseB
|
66
|
+
signature: fa39253035cfe44c8638b8f5d7a3402e
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'yaml'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
# other libraries could fetch the test data from Github.
|
6
|
+
file = File.join(__dir__, 'acceptance_data.yml')
|
7
|
+
tests = YAML::load_file(file)
|
8
|
+
|
9
|
+
describe 'Multiplatform compatibility acceptance tests' do
|
10
|
+
tests.each do |test|
|
11
|
+
input = JSON.parse(test['json'].to_json, quirks_mode: true)
|
12
|
+
signature = test['signature']
|
13
|
+
string = test['string']
|
14
|
+
|
15
|
+
specify "#{test['desc']} string" do
|
16
|
+
expect(Crimp.notation(input)).to eq(string)
|
17
|
+
end
|
18
|
+
|
19
|
+
specify "#{test['desc']} signature" do
|
20
|
+
expect(Crimp.signature(input)).to eq(signature)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/spec/crimp_spec.rb
CHANGED
@@ -1,99 +1,299 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
|
-
describe
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
5
|
+
describe '.signature' do
|
6
|
+
it 'will return an md5 hash' do
|
7
|
+
expect(Crimp.signature('a')).to eq 'd132c0567a5964930f9ee5f14e779e32'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '.notation' do
|
12
|
+
it 'returns a string representation of the passed data' do
|
13
|
+
expect(Crimp.notation([123, 'abc'])).to eq('123NabcSA')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '.annotate' do
|
18
|
+
it 'returns an array of tuples representing the value and the type' do
|
19
|
+
expect(Crimp.annotate([123, 'abc'])).to eq([[[123, 'N'], ['abc', 'S']], 'A'])
|
20
|
+
end
|
21
|
+
|
22
|
+
it "returns a tuple [val, 'N'] for numeric primitives" do
|
23
|
+
expect(Crimp.annotate(123)).to eq([123, 'N'])
|
24
|
+
end
|
25
|
+
|
26
|
+
it "returns a tuple [val, 'S'] for string primitives" do
|
27
|
+
expect(Crimp.annotate('abc')).to eq(['abc', 'S'])
|
28
|
+
end
|
29
|
+
|
30
|
+
it "returns a tuple [[], 'A'] for empty arrays" do
|
31
|
+
expect(Crimp.annotate([])).to eq([[], 'A'])
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe 'Strings' do
|
36
|
+
it 'handles strings' do
|
37
|
+
expect(Crimp.annotate('a')).to eq(['a', 'S'])
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'handles capitalised strings with no modifications' do
|
41
|
+
expect(Crimp.annotate('A')).to eq(['A', 'S'])
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'handles utf-8 strings' do
|
45
|
+
expect(Crimp.annotate('å')).to eq(['å', 'S'])
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'treats symbols like strings' do
|
49
|
+
expect(Crimp.annotate(:a)).to eq(['a', 'S'])
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'treats empty strings like strings' do
|
53
|
+
expect(Crimp.annotate('')).to eq(['', 'S'])
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'Numbers' do
|
58
|
+
it 'handles integers' do
|
59
|
+
expect(Crimp.annotate(1)).to eq([1, 'N'])
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'handles floats' do
|
63
|
+
expect(Crimp.annotate(3.14)).to eq([3.14, 'N'])
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'handles bignums' do
|
67
|
+
bignum = 10_000_000_000_000_000_000
|
68
|
+
|
69
|
+
expect(Crimp.annotate(bignum)).to eq([bignum, 'N'])
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'Nils' do
|
74
|
+
it 'handles nils' do
|
75
|
+
expect(Crimp.annotate(nil)).to eq([nil, '_'])
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'Booleans' do
|
80
|
+
it 'handles falsey values' do
|
81
|
+
expect(Crimp.annotate(false)).to eq([false, 'B'])
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'handles truthy values' do
|
85
|
+
expect(Crimp.annotate(true)).to eq([true, 'B'])
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe 'Arrays' do
|
90
|
+
it 'handles arrays as collection of primitives' do
|
91
|
+
expect(Crimp.annotate([1, 2])).to eq([[[1, 'N'], [2, 'N']], 'A'])
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'sorts arrays' do
|
95
|
+
expect(Crimp.annotate([2, 1])).to eq([[[1, 'N'], [2, 'N']], 'A'])
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'returns the same signature for two arrays containing the same (unordered) values' do
|
99
|
+
arr1 = [1, 2, 3]
|
100
|
+
arr2 = [2, 1, 3]
|
101
|
+
|
102
|
+
expect(Crimp.signature(arr1)).to eq(Crimp.signature(arr2))
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'does not return the same signature for two arrays containing different values' do
|
106
|
+
arr1 = [1, 2, 3]
|
107
|
+
arr2 = ['1', '2', '3']
|
108
|
+
|
109
|
+
expect(Crimp.signature(arr1)).to_not eq(Crimp.signature(arr2))
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'sorts an array with mixed strings and symbols' do
|
113
|
+
expect(Crimp.notation(["b", :a, "c"])).to eq 'aSbScSA'
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe 'Nested Arrays' do
|
118
|
+
it 'sorts arrays with a single nested array' do
|
119
|
+
expect(Crimp.notation([3, [4, 2], 1])).to eq('1N3N2N4NAA')
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'sorts arrays with a multiple nested arrays' do
|
123
|
+
expect(Crimp.notation([3, [4, 2], 1, [6, 5]])).to eq('1N3N2N4NA5N6NAA')
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe 'Hashes' do
|
128
|
+
it 'handles hashes as collection of primitives' do
|
129
|
+
expected = [
|
130
|
+
[
|
131
|
+
[
|
132
|
+
[
|
133
|
+
['a', 'S'],
|
134
|
+
['b', 'S']
|
135
|
+
],
|
136
|
+
'A'
|
137
|
+
]
|
138
|
+
],
|
139
|
+
'H'
|
140
|
+
]
|
141
|
+
|
142
|
+
expect(Crimp.annotate({a: 'b'})).to eq(expected)
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'sorts hashes by key and then sorts the resulting pair of tuples' do
|
146
|
+
expected = [
|
147
|
+
[
|
148
|
+
[
|
149
|
+
[
|
150
|
+
[1, 'N'],
|
151
|
+
['e', 'S']
|
152
|
+
],
|
153
|
+
'A'
|
154
|
+
],
|
155
|
+
[
|
156
|
+
[
|
157
|
+
['a', 'S'],
|
158
|
+
['b', 'S']
|
159
|
+
],
|
160
|
+
'A'
|
161
|
+
],
|
162
|
+
[
|
163
|
+
[
|
164
|
+
['c', 'S'],
|
165
|
+
['f', 'S']
|
166
|
+
],
|
167
|
+
'A'
|
168
|
+
]
|
169
|
+
],
|
170
|
+
'H'
|
171
|
+
]
|
172
|
+
|
173
|
+
expect(Crimp.annotate({ a: 'b', f: 'c', 'e' => 1 })).to eq(expected)
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'returns the same signature for two hashes containing the same (unordered) values' do
|
177
|
+
hsh1 = { a: 2, b: 1 }
|
178
|
+
hsh2 = { b: 1, a: 2 }
|
179
|
+
|
180
|
+
expect(Crimp.signature(hsh1)).to eq(Crimp.signature(hsh2))
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'does not return the same signature for two hashes containing the different values' do
|
184
|
+
hsh1 = { a: 1, b: 2 }
|
185
|
+
hsh2 = { a: 2, b: 1 }
|
186
|
+
|
187
|
+
expect(Crimp.signature(hsh1)).to_not eq(Crimp.signature(hsh2))
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'sorts an hash with mixed key types' do
|
191
|
+
expect(Crimp.notation({:b => "c", "d" => "a"})).to eq 'aSdSAbScSAH'
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
describe 'Sets' do
|
196
|
+
it 'handles sets as arrays' do
|
197
|
+
expect(Crimp.annotate(Set.new([1, 2]))).to eq([[[1, 'N'], [2, 'N']], 'A'])
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'produces the same signature for Array Sets and Arrays' do
|
201
|
+
expect(Crimp.signature(Set.new([1, 2]))).to eq(Crimp.signature([2, 1]))
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'handles Hash sets as arrays' do
|
205
|
+
expect(Crimp.annotate(Set.new({ 1 => 2 }))).to eq([[[[[1, "N"], [2, "N"]], "A"]], "A"])
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'does NOT produce the same signature for Hash Sets and Hashes' do
|
209
|
+
expect(Crimp.signature(Set.new({ 1 => 2 }))).to_not eq(Crimp.signature({ 1 => 2 }))
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'sorts sets as arrays' do
|
213
|
+
expect(Crimp.annotate(Set.new([2, 1]))).to eq([[[1, 'N'], [2, 'N']], 'A'])
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
describe 'nested data structures' do
|
218
|
+
it 'handles a hash with nested arrays and hashes' do
|
219
|
+
obj = { a: [1, 2], b: { c: 'd' } }
|
220
|
+
|
221
|
+
expected = [
|
222
|
+
[
|
223
|
+
[
|
224
|
+
[
|
225
|
+
[
|
226
|
+
[
|
227
|
+
[1, 'N'],
|
228
|
+
[2, 'N']
|
229
|
+
],
|
230
|
+
'A'
|
231
|
+
],
|
232
|
+
['a', 'S']
|
233
|
+
],
|
234
|
+
'A'
|
235
|
+
],
|
236
|
+
[
|
237
|
+
[
|
238
|
+
['b', 'S'],
|
239
|
+
[
|
240
|
+
[
|
241
|
+
[
|
242
|
+
[
|
243
|
+
['c', 'S'],
|
244
|
+
['d', 'S']
|
245
|
+
],
|
246
|
+
'A']
|
247
|
+
],
|
248
|
+
'H']
|
249
|
+
],
|
250
|
+
'A']
|
251
|
+
],
|
252
|
+
'H'
|
253
|
+
]
|
254
|
+
|
255
|
+
expect(Crimp.annotate(obj)).to eq(expected)
|
256
|
+
end
|
257
|
+
|
258
|
+
it 'handles an array of hashes' do
|
259
|
+
obj = [{ a: 1 }, { b: 2 }]
|
260
|
+
expected= [
|
261
|
+
[
|
262
|
+
[
|
263
|
+
[
|
264
|
+
[
|
265
|
+
[
|
266
|
+
[1, 'N'],
|
267
|
+
['a', 'S']
|
268
|
+
],
|
269
|
+
'A'
|
270
|
+
]
|
271
|
+
],
|
272
|
+
'H'
|
273
|
+
],
|
274
|
+
[
|
275
|
+
[
|
276
|
+
[
|
277
|
+
[
|
278
|
+
[2, 'N'],
|
279
|
+
['b', 'S']
|
280
|
+
],
|
281
|
+
'A'
|
282
|
+
]
|
283
|
+
],
|
284
|
+
'H'
|
285
|
+
]
|
286
|
+
],
|
287
|
+
'A'
|
288
|
+
]
|
289
|
+
|
290
|
+
expect(Crimp.annotate(obj)).to eq(expected)
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
describe 'Objects' do
|
295
|
+
it 'raise an error if not in the list of allowed primitives' do
|
296
|
+
expect { Crimp.signature(Object.new) }
|
297
|
+
.to raise_error(TypeError, 'Expected a (String|Number|Boolean|Nil|Hash|Array), Got Object.')
|
98
298
|
end
|
99
299
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,59 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: crimp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- BBC News
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-08-
|
11
|
+
date: 2018-08-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '1.5'
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '1.5'
|
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
|
-
- !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: rake-rspec
|
57
15
|
requirement: !ruby/object:Gem::Requirement
|
58
16
|
requirements:
|
59
17
|
- - ">="
|
@@ -67,49 +25,7 @@ dependencies:
|
|
67
25
|
- !ruby/object:Gem::Version
|
68
26
|
version: '0'
|
69
27
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: guard
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: guard-rspec
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: pry
|
28
|
+
name: rake
|
113
29
|
requirement: !ruby/object:Gem::Requirement
|
114
30
|
requirements:
|
115
31
|
- - ">="
|
@@ -123,7 +39,7 @@ dependencies:
|
|
123
39
|
- !ruby/object:Gem::Version
|
124
40
|
version: '0'
|
125
41
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
42
|
+
name: rspec
|
127
43
|
requirement: !ruby/object:Gem::Requirement
|
128
44
|
requirements:
|
129
45
|
- - ">="
|
@@ -137,22 +53,21 @@ dependencies:
|
|
137
53
|
- !ruby/object:Gem::Version
|
138
54
|
version: '0'
|
139
55
|
- !ruby/object:Gem::Dependency
|
140
|
-
name:
|
56
|
+
name: deepsort
|
141
57
|
requirement: !ruby/object:Gem::Requirement
|
142
58
|
requirements:
|
143
59
|
- - ">="
|
144
60
|
- !ruby/object:Gem::Version
|
145
61
|
version: '0'
|
146
|
-
type: :
|
62
|
+
type: :runtime
|
147
63
|
prerelease: false
|
148
64
|
version_requirements: !ruby/object:Gem::Requirement
|
149
65
|
requirements:
|
150
66
|
- - ">="
|
151
67
|
- !ruby/object:Gem::Version
|
152
68
|
version: '0'
|
153
|
-
description:
|
154
|
-
|
155
|
-
All credit should go to http://stackoverflow.com/users/394282/luke
|
69
|
+
description: Platform agnostic MD5 hash from simple data structures made of numbers,
|
70
|
+
strings, booleans, nil, arrays or hashes.
|
156
71
|
email:
|
157
72
|
- D&ENewsFrameworksTeam@bbc.co.uk
|
158
73
|
executables: []
|
@@ -163,17 +78,16 @@ files:
|
|
163
78
|
- ".ruby-version"
|
164
79
|
- ".travis.yml"
|
165
80
|
- Gemfile
|
166
|
-
- Guardfile
|
167
81
|
- LICENSE.txt
|
168
82
|
- README.md
|
169
83
|
- Rakefile
|
170
84
|
- crimp.gemspec
|
171
85
|
- lib/crimp.rb
|
172
|
-
-
|
173
|
-
- spec/
|
86
|
+
- spec/acceptance_data.yml
|
87
|
+
- spec/acceptance_spec.rb
|
174
88
|
- spec/crimp_spec.rb
|
175
89
|
- spec/spec_helper.rb
|
176
|
-
homepage:
|
90
|
+
homepage: https://www.bbc.co.uk/news
|
177
91
|
licenses:
|
178
92
|
- MIT
|
179
93
|
metadata: {}
|
@@ -196,8 +110,9 @@ rubyforge_project:
|
|
196
110
|
rubygems_version: 2.7.6
|
197
111
|
signing_key:
|
198
112
|
specification_version: 4
|
199
|
-
summary:
|
113
|
+
summary: Creates an MD5 hash from simple data structures.
|
200
114
|
test_files:
|
201
|
-
- spec/
|
115
|
+
- spec/acceptance_data.yml
|
116
|
+
- spec/acceptance_spec.rb
|
202
117
|
- spec/crimp_spec.rb
|
203
118
|
- spec/spec_helper.rb
|
data/Guardfile
DELETED
data/lib/crimp/version.rb
DELETED
data/spec/consistency_spec.rb
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Crimp do
|
4
|
-
describe '.signature' do
|
5
|
-
context 'check MD5 consistent across versions' do
|
6
|
-
context 'given a Hash' do
|
7
|
-
let(:hash) do
|
8
|
-
{
|
9
|
-
a: 123,
|
10
|
-
b: 1.23,
|
11
|
-
c: 'string',
|
12
|
-
d: :sym
|
13
|
-
}
|
14
|
-
end
|
15
|
-
let(:md5) { '1dd744d51279187cc08cabe240f98be2' }
|
16
|
-
|
17
|
-
specify { expect(subject.signature(hash)).to eq md5 }
|
18
|
-
end
|
19
|
-
|
20
|
-
context 'given legacy Hash' do
|
21
|
-
let(:hash) do
|
22
|
-
{ a: { b: 'b', c: 'c' }, d: 'd' }
|
23
|
-
end
|
24
|
-
let(:md5) { '68d07febc4f47f56fa6ef5de063a77b1' }
|
25
|
-
|
26
|
-
specify { expect(subject.signature(hash)).to eq md5 }
|
27
|
-
end
|
28
|
-
|
29
|
-
context 'given an Array' do
|
30
|
-
let(:array) { [123, 1.23, 'string', :sym] }
|
31
|
-
let(:md5) { 'cd29980f258eef3faceca4f4da02ec65' }
|
32
|
-
|
33
|
-
specify { expect(subject.signature(array)).to eq md5 }
|
34
|
-
end
|
35
|
-
|
36
|
-
context 'given legacy Array' do
|
37
|
-
let(:array) { [1, 2, 3, [4, [5, 6]]] }
|
38
|
-
let(:md5) { '4dc4e1161c9315db0bc43c0201b3ec05' }
|
39
|
-
|
40
|
-
specify { expect(subject.signature(array)).to eq md5 }
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|