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 ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in hash_digest.gemspec
4
+ gemspec
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
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+ Rake::TestTask.new(:test) do |test|
6
+ test.libs << 'lib' << 'test'
7
+ test.pattern = 'test/**/test_*.rb'
8
+ test.verbose = true
9
+ end
10
+
11
+ task :default => :test
@@ -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
@@ -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
@@ -0,0 +1,3 @@
1
+ module HashDigest
2
+ VERSION = "1.0.0"
3
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/setup'
2
+ require 'minitest/spec'
3
+ require 'minitest/autorun'
4
+
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+ require 'hash_digest'
8
+
9
+ class MiniTest::Unit::TestCase
10
+ end
@@ -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