hash_digest 1.0.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.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.markdown +40 -0
- data/Rakefile +11 -0
- data/hash_digest.gemspec +28 -0
- data/lib/hash_digest.rb +27 -0
- data/lib/hash_digest/version.rb +3 -0
- data/test/helper.rb +10 -0
- data/test/test_hash_digest.rb +24 -0
- metadata +90 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.markdown
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
= HashHash
|
2
|
+
|
3
|
+
Generates MD5 digests of Hashes (and Arrays) indifferent to key type and ordering.
|
4
|
+
|
5
|
+
Useful for hashing rows in a 2-dimensional table.
|
6
|
+
|
7
|
+
Used by the [remote_table](https://github.com/seamusabshere/remote_table) gem.
|
8
|
+
|
9
|
+
== Example
|
10
|
+
|
11
|
+
=== Indifferent to key type
|
12
|
+
|
13
|
+
HashDigest.hexdigest(:a => 1) #=> '3872c9ae3f427af0be0ead09d07ae2cf'
|
14
|
+
HashDigest.hexdigest('a' => 1) #=> '3872c9ae3f427af0be0ead09d07ae2cf'
|
15
|
+
|
16
|
+
=== Indifferent to key order
|
17
|
+
|
18
|
+
HashDigest.hexdigest(:a => 1, 'b' => 2) == HashDigest.hexdigest('a' => 1, :b => 2) # true
|
19
|
+
HashDigest.hexdigest(:a => 1, 'b' => 2) == HashDigest.hexdigest(:b => 2, 'a' => 1) # true
|
20
|
+
|
21
|
+
== Algorithm
|
22
|
+
|
23
|
+
Basically represent the hash as a URL querystring, ordered by key, and MD5 that.
|
24
|
+
|
25
|
+
1. Stringify keys
|
26
|
+
2. Create an array of strings like "url_encode(key)=url_encode(value)" by going through each key in alphabetical order
|
27
|
+
3. Join the array together with "&"
|
28
|
+
4. MD5 hexdigest the joined string
|
29
|
+
|
30
|
+
To digest an array, just pretend it's a hash with keys like 1, 2, 3, etc.
|
31
|
+
|
32
|
+
== Potential issues
|
33
|
+
|
34
|
+
* Uses MD5 (not cryptographically awesome)
|
35
|
+
* Uses ActiveSupport's <tt>#to_query</tt> method to create a digestible string like "foo=bar&baz=bam" (slow)
|
36
|
+
* Meant for flat hashes, e.g. { :a => 1, :b => 2 } and not { :x => { :y => :z } }
|
37
|
+
|
38
|
+
== Copyright
|
39
|
+
|
40
|
+
Copyright 2011 Seamus Abshere
|
data/Rakefile
ADDED
data/hash_digest.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "hash_digest/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "hash_digest"
|
7
|
+
s.version = HashDigest::VERSION
|
8
|
+
s.authors = ["Seamus Abshere"]
|
9
|
+
s.email = ["seamus@abshere.net"]
|
10
|
+
s.homepage = "https://github.com/seamusabshere/hash_digest"
|
11
|
+
s.summary = %q{Make consistent hashcodes from flat Hashes, regardless of key ordering}
|
12
|
+
s.description = %q{Make consistent hashcodes from flat Hashes, regardless of key ordering. Useful for hashing rows in a table.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "hash_digest"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
# s.add_runtime_dependency "rest-client"
|
24
|
+
s.add_runtime_dependency 'activesupport'
|
25
|
+
|
26
|
+
s.add_development_dependency 'minitest'
|
27
|
+
s.add_development_dependency 'rake'
|
28
|
+
end
|
data/lib/hash_digest.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
require 'active_support'
|
3
|
+
require 'active_support/version'
|
4
|
+
%w{
|
5
|
+
active_support/core_ext/hash/keys
|
6
|
+
active_support/core_ext/object/to_query
|
7
|
+
}.each do |active_support_3_requirement|
|
8
|
+
require active_support_3_requirement
|
9
|
+
end if ::ActiveSupport::VERSION::MAJOR >= 3
|
10
|
+
|
11
|
+
require "hash_digest/version"
|
12
|
+
|
13
|
+
module HashDigest
|
14
|
+
def self.hexdigest(hsh)
|
15
|
+
ordered_list = if hsh.is_a?(::Hash)
|
16
|
+
hsh = hsh.stringify_keys
|
17
|
+
hsh.keys.sort.map { |k| hsh[k].to_query k }
|
18
|
+
elsif hsh.is_a?(::Array)
|
19
|
+
ary = []
|
20
|
+
hsh.each_with_index { |v, i| ary.push v.to_query(i.to_s) }
|
21
|
+
ary
|
22
|
+
else
|
23
|
+
raise ::ArgumentError, "[hash_digest gem] Can only digest Hashes and Arrays, not #{hsh.class}"
|
24
|
+
end
|
25
|
+
::Digest::MD5.hexdigest ordered_list.join('&')
|
26
|
+
end
|
27
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require 'helper'
|
3
|
+
|
4
|
+
describe HashDigest do
|
5
|
+
it 'generates a hash of a hash' do
|
6
|
+
HashDigest.hexdigest(:a => 1).must_equal '3872c9ae3f427af0be0ead09d07ae2cf'
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'is indifferent to key type' do
|
10
|
+
HashDigest.hexdigest(:a => 1, 'b' => 2).must_equal(HashDigest.hexdigest('a' => 1, :b => 2))
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'is indifferent to key order' do
|
14
|
+
HashDigest.hexdigest(:a => 1, 'b' => 2).must_equal(HashDigest.hexdigest(:b => 2, 'a' => 1))
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'just as a bonus, works on arrays' do
|
18
|
+
HashDigest.hexdigest([:a, 1]).must_equal '8ce19b95077ec34a4fd06b089f368678'
|
19
|
+
end
|
20
|
+
|
21
|
+
it "raises an exception if you try to digest something it doesn't handle" do
|
22
|
+
lambda { HashDigest.hexdigest('foobar') }.must_raise(::ArgumentError)
|
23
|
+
end
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hash_digest
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Seamus Abshere
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-09-23 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activesupport
|
16
|
+
requirement: &2154254960 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2154254960
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: minitest
|
27
|
+
requirement: &2154254540 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2154254540
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rake
|
38
|
+
requirement: &2154254120 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2154254120
|
47
|
+
description: Make consistent hashcodes from flat Hashes, regardless of key ordering.
|
48
|
+
Useful for hashing rows in a table.
|
49
|
+
email:
|
50
|
+
- seamus@abshere.net
|
51
|
+
executables: []
|
52
|
+
extensions: []
|
53
|
+
extra_rdoc_files: []
|
54
|
+
files:
|
55
|
+
- .gitignore
|
56
|
+
- Gemfile
|
57
|
+
- README.markdown
|
58
|
+
- Rakefile
|
59
|
+
- hash_digest.gemspec
|
60
|
+
- lib/hash_digest.rb
|
61
|
+
- lib/hash_digest/version.rb
|
62
|
+
- test/helper.rb
|
63
|
+
- test/test_hash_digest.rb
|
64
|
+
homepage: https://github.com/seamusabshere/hash_digest
|
65
|
+
licenses: []
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options: []
|
68
|
+
require_paths:
|
69
|
+
- lib
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ! '>='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
requirements: []
|
83
|
+
rubyforge_project: hash_digest
|
84
|
+
rubygems_version: 1.8.6
|
85
|
+
signing_key:
|
86
|
+
specification_version: 3
|
87
|
+
summary: Make consistent hashcodes from flat Hashes, regardless of key ordering
|
88
|
+
test_files:
|
89
|
+
- test/helper.rb
|
90
|
+
- test/test_hash_digest.rb
|