lycopodium 0.0.1
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 +7 -0
- data/.gitignore +6 -0
- data/.travis.yml +3 -0
- data/.yardopts +4 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +103 -0
- data/Rakefile +16 -0
- data/USAGE +1 -0
- data/lib/lycopodium/version.rb +3 -0
- data/lib/lycopodium.rb +71 -0
- data/lycopodium.gemspec +20 -0
- data/spec/spec_helper.rb +3 -0
- metadata +85 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 647237749059c644529c2ddb5887e8a6d3aa61df
|
4
|
+
data.tar.gz: ac48dee2979e40b13b3e8b3635ab5d07825961ee
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5c063aec1bb6ade2ddebc89b540566c39472d09f0c15342c3ff091a0aa7b2fd57ddf51cf22cebbed7a946dd51e87191e88a62a494b682fe1db4dfa1b27d725be
|
7
|
+
data.tar.gz: 9f53c88a5b548ceef3ccd12bb82dc1d25e8efaa786b754da0020d2a34d8e1ba46f9564b032f6fb80f42fdee5419050873a1d329f63292f3526d372c63158c38a
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/.yardopts
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2013 Open North Inc.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
# Lycopodium Finds Fingerprints
|
2
|
+
|
3
|
+
[](http://travis-ci.org/opennorth/lycopodium)
|
4
|
+
[](https://gemnasium.com/opennorth/lycopodium)
|
5
|
+
[](https://coveralls.io/r/opennorth/lycopodium)
|
6
|
+
[](https://codeclimate.com/github/opennorth/lycopodium)
|
7
|
+
|
8
|
+
Test what transformations you can make to a set of values without creating collisions.
|
9
|
+
|
10
|
+
> Historically, Lycopodium powder, the spores of Lycopodium and related plants, was used as a fingerprint powder. – [Wikipedia](http://en.wikipedia.org/wiki/Fingerprint_powder#Composition)
|
11
|
+
|
12
|
+
## Usage
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
require 'lycopodium'
|
16
|
+
```
|
17
|
+
|
18
|
+
First, write a method that transforms a value, for example:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
meth1 = ->(string) do
|
22
|
+
string.gsub(/\p{Space}/, '')
|
23
|
+
end
|
24
|
+
```
|
25
|
+
|
26
|
+
Then, initialize a `Lycopodium` instance with a set of values and the transformation method:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
set = Lycopodium.new(["foo", "f o o"], meth1)
|
30
|
+
```
|
31
|
+
|
32
|
+
Lastly, test whether the method creates collisions between the members of the set:
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
set.value_to_fingerprint
|
36
|
+
```
|
37
|
+
|
38
|
+
In this example, an exception will be raised, because the method creates collisions:
|
39
|
+
|
40
|
+
Lycopodium::Collision: "foo", "f o o" => "foo"
|
41
|
+
|
42
|
+
With another method that, for example, uppercases a string and creates no collisions:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
meth2 = ->(string) do
|
46
|
+
string.upcase
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
It will return the mapping from original to transformed string:
|
51
|
+
|
52
|
+
{"foo" => "FOO", "f o o" => "F O O"}
|
53
|
+
|
54
|
+
We thus learn that whitespace disambiguates between members of the set, but letter case does not.
|
55
|
+
|
56
|
+
To remove all members of the set that collide after transformation, run:
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
set_without_collisions = set.reject_collisions
|
60
|
+
```
|
61
|
+
|
62
|
+
A `Lycopodium` instance otherwise behaves as an array.
|
63
|
+
|
64
|
+
## Method definition
|
65
|
+
|
66
|
+
Besides the `->` syntax above, you can define the same method as:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
meth = lambda do |string|
|
70
|
+
string.gsub(/\p{Space}/, '')
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
74
|
+
Or:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
meth = proc do |string|
|
78
|
+
string.gsub(/\p{Space}/, '')
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
Or:
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
meth = Proc.new do |string|
|
86
|
+
string.gsub(/\p{Space}/, '')
|
87
|
+
end
|
88
|
+
```
|
89
|
+
|
90
|
+
Or even:
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
def func(string)
|
94
|
+
string.gsub(/\p{Space}/, '')
|
95
|
+
end
|
96
|
+
meth = Object.method(:func)
|
97
|
+
```
|
98
|
+
|
99
|
+
## Bugs? Questions?
|
100
|
+
|
101
|
+
This project's main repository is on GitHub: [http://github.com/opennorth/lycopodium](http://github.com/opennorth/lycopodium), where your contributions, forks, bug reports, feature requests, and feedback are greatly welcomed.
|
102
|
+
|
103
|
+
Copyright (c) 2013 Open North Inc., released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
|
7
|
+
task :default => :spec
|
8
|
+
|
9
|
+
begin
|
10
|
+
require 'yard'
|
11
|
+
YARD::Rake::YardocTask.new
|
12
|
+
rescue LoadError
|
13
|
+
task :yard do
|
14
|
+
abort 'YARD is not available. In order to run yard, you must: gem install yard'
|
15
|
+
end
|
16
|
+
end
|
data/USAGE
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
See README.md for full usage details.
|
data/lib/lycopodium.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require "set"
|
2
|
+
|
3
|
+
class Lycopodium < Array
|
4
|
+
class Error < StandardError; end
|
5
|
+
class Collision < Error; end
|
6
|
+
|
7
|
+
attr_accessor :function
|
8
|
+
|
9
|
+
# @param [Array] set a set of values
|
10
|
+
# @param [Proc] function a method that transforms a value
|
11
|
+
def initialize(set, function = lambda{|value| value})
|
12
|
+
replace(set)
|
13
|
+
self.function = function
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return [Array] the members of the set without collisions
|
17
|
+
def reject_collisions
|
18
|
+
hashes, collisions = hashes_and_collisions
|
19
|
+
|
20
|
+
items = hashes.reject do |_,hash|
|
21
|
+
collisions.include?(hash)
|
22
|
+
end.map do |item,_|
|
23
|
+
item
|
24
|
+
end
|
25
|
+
|
26
|
+
self.class.new(items, function)
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Hash] a mapping from the original to the transformed value
|
30
|
+
# @raise [Collision] if the method creates collisions between members of the set
|
31
|
+
def value_to_fingerprint
|
32
|
+
hashes, collisions = hashes_and_collisions
|
33
|
+
|
34
|
+
unless collisions.empty?
|
35
|
+
message = []
|
36
|
+
collisions.each do |collision|
|
37
|
+
items = hashes.select do |_,hash|
|
38
|
+
hash == collision
|
39
|
+
end.map do |item,_|
|
40
|
+
item
|
41
|
+
end
|
42
|
+
message << %(#{items.map(&:inspect) * ", "} => "#{collision}")
|
43
|
+
end
|
44
|
+
raise Collision, message * "\n"
|
45
|
+
end
|
46
|
+
|
47
|
+
hashes
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def hashes_and_collisions
|
53
|
+
collisions = Set.new
|
54
|
+
|
55
|
+
hashes = {}
|
56
|
+
counts = {}
|
57
|
+
|
58
|
+
each do |item|
|
59
|
+
unless hashes.key?(item)
|
60
|
+
hashes[item] = function.call(item)
|
61
|
+
end
|
62
|
+
if counts.key?(hashes[item])
|
63
|
+
collisions << hashes[item]
|
64
|
+
else
|
65
|
+
counts[hashes[item]] = 1
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
[hashes, collisions]
|
70
|
+
end
|
71
|
+
end
|
data/lycopodium.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/lycopodium/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "lycopodium"
|
6
|
+
s.version = Lycopodium::VERSION
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.authors = ["Open North"]
|
9
|
+
s.email = ["info@opennorth.ca"]
|
10
|
+
s.homepage = "http://github.com/opennorth/lycopodium"
|
11
|
+
s.summary = %q{Test what transformations you can make to a set of unique strings without creating collisions}
|
12
|
+
|
13
|
+
s.files = `git ls-files`.split("\n")
|
14
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
|
18
|
+
s.add_development_dependency('rspec', '~> 2.10')
|
19
|
+
s.add_development_dependency('rake')
|
20
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lycopodium
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Open North
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-06-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.10'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.10'
|
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
|
+
description:
|
42
|
+
email:
|
43
|
+
- info@opennorth.ca
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- .gitignore
|
49
|
+
- .travis.yml
|
50
|
+
- .yardopts
|
51
|
+
- Gemfile
|
52
|
+
- LICENSE
|
53
|
+
- README.md
|
54
|
+
- Rakefile
|
55
|
+
- USAGE
|
56
|
+
- lib/lycopodium.rb
|
57
|
+
- lib/lycopodium/version.rb
|
58
|
+
- lycopodium.gemspec
|
59
|
+
- spec/spec_helper.rb
|
60
|
+
homepage: http://github.com/opennorth/lycopodium
|
61
|
+
licenses: []
|
62
|
+
metadata: {}
|
63
|
+
post_install_message:
|
64
|
+
rdoc_options: []
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 2.0.0
|
80
|
+
signing_key:
|
81
|
+
specification_version: 4
|
82
|
+
summary: Test what transformations you can make to a set of unique strings without
|
83
|
+
creating collisions
|
84
|
+
test_files:
|
85
|
+
- spec/spec_helper.rb
|