bit_hash 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +32 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +97 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/bit_hash.gemspec +70 -0
- data/lib/bit_hash.rb +272 -0
- data/spec/bit_hash_spec.rb +104 -0
- data/spec/spec_helper.rb +12 -0
- metadata +137 -0
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
gem "to_insane", ">=0.2.1"
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem "shoulda", ">= 0"
|
10
|
+
gem "bundler", "~> 1.0.0"
|
11
|
+
gem "jeweler", "~> 1.5.2"
|
12
|
+
gem "rcov", ">= 0"
|
13
|
+
gem "rspec"
|
14
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.1.2)
|
5
|
+
git (1.2.5)
|
6
|
+
jeweler (1.5.2)
|
7
|
+
bundler (~> 1.0.0)
|
8
|
+
git (>= 1.2.5)
|
9
|
+
rake
|
10
|
+
rake (0.8.7)
|
11
|
+
rcov (0.9.9)
|
12
|
+
rspec (2.5.0)
|
13
|
+
rspec-core (~> 2.5.0)
|
14
|
+
rspec-expectations (~> 2.5.0)
|
15
|
+
rspec-mocks (~> 2.5.0)
|
16
|
+
rspec-core (2.5.1)
|
17
|
+
rspec-expectations (2.5.0)
|
18
|
+
diff-lcs (~> 1.1.2)
|
19
|
+
rspec-mocks (2.5.0)
|
20
|
+
shoulda (2.11.3)
|
21
|
+
to_insane (0.2.1)
|
22
|
+
|
23
|
+
PLATFORMS
|
24
|
+
ruby
|
25
|
+
|
26
|
+
DEPENDENCIES
|
27
|
+
bundler (~> 1.0.0)
|
28
|
+
jeweler (~> 1.5.2)
|
29
|
+
rcov
|
30
|
+
rspec
|
31
|
+
shoulda
|
32
|
+
to_insane (>= 0.2.1)
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Ryan Ong
|
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.rdoc
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
= bit_hash
|
2
|
+
|
3
|
+
A simple class that can convert an option hash into a compact string.
|
4
|
+
|
5
|
+
== Usage
|
6
|
+
|
7
|
+
When writing these config maps. Try to put the mose used options first so the string can be shorter.
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
require 'bit_hash'
|
11
|
+
|
12
|
+
config_map = [
|
13
|
+
{
|
14
|
+
:name => :air, # name of option
|
15
|
+
:options => 2, # number of options must be 2 or greater
|
16
|
+
},
|
17
|
+
{
|
18
|
+
:name => :color,
|
19
|
+
:options => ['blue','green','red'] # bit_hash can map arrays of data, the default setting will be the first value in the array
|
20
|
+
},
|
21
|
+
{
|
22
|
+
:name => :body_style,
|
23
|
+
:options => [:sedan,:mini_van,:suv], # Array values can be anything that can be found using the Array#index function
|
24
|
+
:default => :mini_van # for arrays the default is any array value
|
25
|
+
},
|
26
|
+
{
|
27
|
+
:name => :transmission, # name of option
|
28
|
+
:options => 6,
|
29
|
+
:default => 5 # for numbers the default must be between 0 and the options value
|
30
|
+
},
|
31
|
+
{
|
32
|
+
:name => :min_price,
|
33
|
+
:options => (50..100).to_a, # ( just a way to store ranges of numbers)
|
34
|
+
:default => 60 # basically any default can be used as long as it is a valid option
|
35
|
+
},
|
36
|
+
{
|
37
|
+
:name => :max_price,
|
38
|
+
|
39
|
+
# intervals of 20 starting at 10000 (just a way to store ranges of numbers)
|
40
|
+
:options => (1..5).to_a.map {|n| 10000+(n*20)},
|
41
|
+
|
42
|
+
# you can use :default_index option to reference something in the option arrays but it really isn't suggested, :default take precedence
|
43
|
+
:default_index => 2
|
44
|
+
}
|
45
|
+
]
|
46
|
+
|
47
|
+
# initialize
|
48
|
+
@config = BitHash.new(config_map)
|
49
|
+
|
50
|
+
# set a single value
|
51
|
+
@config[:color]='red'
|
52
|
+
|
53
|
+
# get a value
|
54
|
+
@config[:value]
|
55
|
+
|
56
|
+
# replace values in config with another hash
|
57
|
+
@config.replace({:air=>1})
|
58
|
+
|
59
|
+
# parse a string without saving
|
60
|
+
@config.parse('e')
|
61
|
+
|
62
|
+
# parse a string and save it
|
63
|
+
@config.save
|
64
|
+
|
65
|
+
# convert to small compact string
|
66
|
+
@config.to_s
|
67
|
+
|
68
|
+
== TODO
|
69
|
+
|
70
|
+
* Impliment more tests
|
71
|
+
* Clone more Hash functions
|
72
|
+
* Storage of strings
|
73
|
+
* If binary options and default 1, user inverse
|
74
|
+
* allow a hash for config_map for ruby 1.9
|
75
|
+
* Add some sort of ActiveRecord extender
|
76
|
+
|
77
|
+
== Contributing to bit_hash
|
78
|
+
|
79
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
80
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
81
|
+
* Fork the project
|
82
|
+
* Start a feature/bugfix branch
|
83
|
+
* Commit and push until you are happy with your contribution
|
84
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
85
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
86
|
+
|
87
|
+
== Credits
|
88
|
+
|
89
|
+
Ryan Ong - ryanong@gmail.com
|
90
|
+
|
91
|
+
Developed for and with CarZen[link:http://carzen.com]
|
92
|
+
|
93
|
+
== Copyright
|
94
|
+
|
95
|
+
Copyright (c) 2011 Ryan Ong. See LICENSE.txt for
|
96
|
+
further details.
|
97
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'rake'
|
11
|
+
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gem|
|
14
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
15
|
+
gem.name = "bit_hash"
|
16
|
+
gem.homepage = "http://github.com/ryanong/bit_hash"
|
17
|
+
gem.license = "MIT"
|
18
|
+
gem.summary = %Q{bit_hash allows you to serialize simple set data into short compact URL safe strings.}
|
19
|
+
gem.description = %Q{bit_hash is a useful tool to pass through options through a string. The best usecases would be forms with binary,trinary, etc etc data sets.}
|
20
|
+
gem.email = "ryanong@gmail.com"
|
21
|
+
gem.authors = ["Ryan Ong"]
|
22
|
+
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
23
|
+
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
24
|
+
# gem.add_development_dependency 'rspec', '> 1.2.3'
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rspec/core'
|
29
|
+
require 'rspec/core/rake_task'
|
30
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
31
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
35
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
36
|
+
spec.rcov = true
|
37
|
+
end
|
38
|
+
|
39
|
+
task :default => :spec
|
40
|
+
|
41
|
+
require 'rake/rdoctask'
|
42
|
+
Rake::RDocTask.new do |rdoc|
|
43
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
44
|
+
|
45
|
+
rdoc.rdoc_dir = 'rdoc'
|
46
|
+
rdoc.title = "bit_hash #{version}"
|
47
|
+
rdoc.rdoc_files.include('README*')
|
48
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
49
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/bit_hash.gemspec
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{bit_hash}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Ryan Ong"]
|
12
|
+
s.date = %q{2011-02-16}
|
13
|
+
s.description = %q{bit_hash is a useful tool to pass through options through a string. The best usecases would be forms with binary,trinary, etc etc data sets.}
|
14
|
+
s.email = %q{ryanong@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".rspec",
|
22
|
+
"Gemfile",
|
23
|
+
"Gemfile.lock",
|
24
|
+
"LICENSE.txt",
|
25
|
+
"README.rdoc",
|
26
|
+
"Rakefile",
|
27
|
+
"VERSION",
|
28
|
+
"bit_hash.gemspec",
|
29
|
+
"lib/bit_hash.rb",
|
30
|
+
"spec/bit_hash_spec.rb",
|
31
|
+
"spec/spec_helper.rb"
|
32
|
+
]
|
33
|
+
s.homepage = %q{http://github.com/ryanong/bit_hash}
|
34
|
+
s.licenses = ["MIT"]
|
35
|
+
s.require_paths = ["lib"]
|
36
|
+
s.rubygems_version = %q{1.5.0}
|
37
|
+
s.summary = %q{bit_hash allows you to serialize simple set data into short compact URL safe strings.}
|
38
|
+
s.test_files = [
|
39
|
+
"spec/bit_hash_spec.rb",
|
40
|
+
"spec/spec_helper.rb"
|
41
|
+
]
|
42
|
+
|
43
|
+
if s.respond_to? :specification_version then
|
44
|
+
s.specification_version = 3
|
45
|
+
|
46
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
47
|
+
s.add_runtime_dependency(%q<to_insane>, [">= 0.2.1"])
|
48
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
49
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
50
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
|
51
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
52
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
53
|
+
else
|
54
|
+
s.add_dependency(%q<to_insane>, [">= 0.2.1"])
|
55
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
56
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
57
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
58
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
59
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
60
|
+
end
|
61
|
+
else
|
62
|
+
s.add_dependency(%q<to_insane>, [">= 0.2.1"])
|
63
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
64
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
65
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
66
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
67
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
data/lib/bit_hash.rb
ADDED
@@ -0,0 +1,272 @@
|
|
1
|
+
require 'to_insane'
|
2
|
+
|
3
|
+
class BitHash
|
4
|
+
|
5
|
+
attr_accessor :options, :default
|
6
|
+
# look below at load_config_map for config_map schema
|
7
|
+
# base is the base value you want to use. Defaults to a URL safe character base which is 63
|
8
|
+
# character set can also be changed but not really necessary. read to_insane doc for more details
|
9
|
+
def initialize(config_map=nil, *options)
|
10
|
+
load_options(options)
|
11
|
+
@config = Hash.new
|
12
|
+
@default = Hash.new
|
13
|
+
#validate mapping
|
14
|
+
load_config_map(config_map) if config_map.kind_of? Array
|
15
|
+
@config
|
16
|
+
end
|
17
|
+
|
18
|
+
#Example config_map
|
19
|
+
#
|
20
|
+
# config_map = [
|
21
|
+
# {
|
22
|
+
# :name => :air, # name of option
|
23
|
+
# :options => 2, # number of options must be 2 or greater
|
24
|
+
# },
|
25
|
+
# {
|
26
|
+
# :name => :color,
|
27
|
+
# :options => ['blue','green','red'] # bit_hash can map arrays of data, the default setting will be the first value in the array
|
28
|
+
# },
|
29
|
+
# {
|
30
|
+
# :name => :body_style,
|
31
|
+
# :options => [:sedan,:mini_van,:suv], # Array values can be anything that can be found using the Array#index function
|
32
|
+
# :default => :mini_van # for arrays the default is any array value
|
33
|
+
# },
|
34
|
+
# {
|
35
|
+
# :name => :transmission, # name of option
|
36
|
+
# :options => 6,
|
37
|
+
# :default => 5 # for numbers the default must be between 0 and the options value
|
38
|
+
# },
|
39
|
+
# {
|
40
|
+
# :name => :min_price,
|
41
|
+
# :options => (50..100).to_a, # ( just a way to store ranges of numbers)
|
42
|
+
# :default => 60 # basically any default can be used as long as it is a valid option
|
43
|
+
# },
|
44
|
+
# {
|
45
|
+
# :name => :max_price,
|
46
|
+
|
47
|
+
# # intervals of 20 starting at 10000 (just a way to store ranges of numbers)
|
48
|
+
# :options => (1..5).to_a.map {|n| 10000+(n*20)},
|
49
|
+
|
50
|
+
# # you can use :default_index option to reference something in the option arrays but it really isn't suggested, :default take precedence
|
51
|
+
# :default_index => 2
|
52
|
+
# }
|
53
|
+
# ]
|
54
|
+
def load_config_map(config_map)
|
55
|
+
raise ArgumentError, "Config Map must be an Array" unless config_map.kind_of? Array
|
56
|
+
config_array = []
|
57
|
+
new_config = {}
|
58
|
+
config_map.each_index do |index|
|
59
|
+
conf = config_map[index]
|
60
|
+
raise ArgumentError, "#{conf[:name]} is a duplicate" if new_config.keys.index(conf[:name])
|
61
|
+
new_config[conf[:name]] = get_check_config(index,conf)
|
62
|
+
config_array[index] = conf
|
63
|
+
end
|
64
|
+
@config = new_config.dup
|
65
|
+
@default = new_config.dup
|
66
|
+
@config_map = config_array
|
67
|
+
end
|
68
|
+
|
69
|
+
# Just get a list of keys
|
70
|
+
def keys
|
71
|
+
@config_map.map{ |c| c[:name]}
|
72
|
+
end
|
73
|
+
|
74
|
+
# Set default key
|
75
|
+
def set_default(key)
|
76
|
+
conf = get_options(key)
|
77
|
+
@config[conf[:name]] = 0
|
78
|
+
if !conf[:default].nil?
|
79
|
+
new_config[conf[:name]] = conf[:default]
|
80
|
+
elsif !conf[:default_index].nil?
|
81
|
+
new_config[conf[:name]] = conf[:options][conf.default_index]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# see set
|
86
|
+
def []=(key,value)
|
87
|
+
set(key,value)
|
88
|
+
end
|
89
|
+
|
90
|
+
# sets a key value, returns nil if value is invalid
|
91
|
+
def set(key,value)
|
92
|
+
conf = get_options(key)
|
93
|
+
if conf && check_value(conf,value)
|
94
|
+
@config[key] = value
|
95
|
+
else
|
96
|
+
nil
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# sets with critical failure
|
101
|
+
def set!(key,value)
|
102
|
+
conf = get_options(key)
|
103
|
+
if conf && check_value!(conf,value)
|
104
|
+
@config[key] = value
|
105
|
+
else
|
106
|
+
raise ArgumentError, "Key: '#{key}' not found in config"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# fetches values for given key
|
111
|
+
def [](key)
|
112
|
+
@config[key]
|
113
|
+
end
|
114
|
+
|
115
|
+
# replaces internal settings with any given hash and overwrites values and returns hash. On failure returns nil
|
116
|
+
def replace(hash)
|
117
|
+
cache = @config.dup
|
118
|
+
hash.each do |key, value|
|
119
|
+
if set(key,value).nil?
|
120
|
+
@config = cache
|
121
|
+
return nil
|
122
|
+
end
|
123
|
+
end
|
124
|
+
@config
|
125
|
+
end
|
126
|
+
|
127
|
+
# returns option settings for given key
|
128
|
+
def get_options(key)
|
129
|
+
index = @config_map.index{|x|x[:name]==key}
|
130
|
+
(index) ? @config_map[index].merge({:index => index}) : nil
|
131
|
+
end
|
132
|
+
|
133
|
+
# replaces given option with name of key and replaces with options
|
134
|
+
def replace_options(key, options)
|
135
|
+
@config_map.map! do |conf|
|
136
|
+
if conf[:name] == key
|
137
|
+
options
|
138
|
+
else
|
139
|
+
conf
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# takes a given config string and returns a mapped hash
|
145
|
+
# please read to_insane doc for info on base and char_set
|
146
|
+
def parse(config_string, *options)
|
147
|
+
load_options(options)
|
148
|
+
raise ArgumentError, "Prefix must be a string" if !@options[:prefix].nil? && !@options[:prefix].kind_of?(String)
|
149
|
+
config_string[0..@options[:prefix].size] = nil unless @options[:prefix].nil?
|
150
|
+
config_string = config_string.from_insane(@options[:base],@options[:char_set]).to_s(2)
|
151
|
+
config_array = config_string.split('')
|
152
|
+
new_config = @default.dup
|
153
|
+
@config_map.each do |conf|
|
154
|
+
value = config_array.pop(conf[:size])
|
155
|
+
break if value.nil?
|
156
|
+
value = value.join('').to_i(2)
|
157
|
+
new_config[conf[:name]] = (conf[:options].kind_of? Array ) ? conf[:options][value] : value
|
158
|
+
end
|
159
|
+
new_config
|
160
|
+
end
|
161
|
+
|
162
|
+
# pareses and saves string into internal hash
|
163
|
+
def save(config_string, *options)
|
164
|
+
@config = parse(config_string, *options)
|
165
|
+
end
|
166
|
+
|
167
|
+
#converts it into a binary string
|
168
|
+
def to_bin
|
169
|
+
bin_config = []
|
170
|
+
@config_map.each do |conf|
|
171
|
+
val = @config[conf[:name]]
|
172
|
+
val = conf[:options].index(val) if conf[:options].kind_of? Array
|
173
|
+
bin = "%0#{conf[:size]}d" % val.to_s(2).to_i
|
174
|
+
bin_config.unshift(bin)
|
175
|
+
end
|
176
|
+
bin_config.join('')
|
177
|
+
end
|
178
|
+
|
179
|
+
#converts it to an integer, Good for IDs
|
180
|
+
def to_i
|
181
|
+
to_bin.to_i(2)
|
182
|
+
end
|
183
|
+
|
184
|
+
# turns hash into a small compact string.
|
185
|
+
# see to_insane rdoc for base, and char_set definitions
|
186
|
+
def to_s(*options)
|
187
|
+
load_options(options)
|
188
|
+
str = ''
|
189
|
+
str << @options[:prefix] if @options[:prefix].kind_of? String
|
190
|
+
str << to_i.to_insane(@options[:base], @options[:char_set])
|
191
|
+
str
|
192
|
+
end
|
193
|
+
|
194
|
+
#checks key to see if value given is valid
|
195
|
+
def valid_value?(key,val)
|
196
|
+
check_value(get_options(key),val)
|
197
|
+
end
|
198
|
+
|
199
|
+
alias_method :to_hash, :inspect
|
200
|
+
|
201
|
+
# returns as a hash (alias: inspect)
|
202
|
+
def to_hash
|
203
|
+
@config
|
204
|
+
end
|
205
|
+
|
206
|
+
private
|
207
|
+
|
208
|
+
# checks value against given config
|
209
|
+
def check_value(conf,val)
|
210
|
+
if conf[:options].kind_of?(Array)
|
211
|
+
return false if conf[:options].index(val).nil?
|
212
|
+
elsif conf[:options].kind_of?(Integer) && val.kind_of?(Integer)
|
213
|
+
return false if val < 0 or val > conf[:options]
|
214
|
+
else
|
215
|
+
return false
|
216
|
+
end
|
217
|
+
true
|
218
|
+
end
|
219
|
+
|
220
|
+
# checks values with a bang
|
221
|
+
def check_value!(conf,val)
|
222
|
+
if conf[:options].kind_of? Array
|
223
|
+
raise ArgumentError, "#{conf[:name]} is #{val} and is not a valid value within the stored array. #{conf[:options].to_s}" if conf[:options].index(val).nil?
|
224
|
+
elsif conf[:options].kind_of? Integer
|
225
|
+
raise ArgumentError, "#{conf[:name]} is #{val} and should not be less than 0" if val < 0
|
226
|
+
raise ArgumentError, "#{conf[:name]} is #{val} and value is not less than #{conf[:options]}" if val > conf[:options]
|
227
|
+
else
|
228
|
+
raise ArgumentError, "#{conf[:name]} is not a valid value please associate it with an object in an array or give it an integer value"
|
229
|
+
end
|
230
|
+
true
|
231
|
+
end
|
232
|
+
|
233
|
+
def load_options(options)
|
234
|
+
if options.kind_of? Array
|
235
|
+
@options = {:base => options[0], :char_set => options[1]}
|
236
|
+
elsif options.kind_of? Hash
|
237
|
+
@options = options
|
238
|
+
end
|
239
|
+
@options[:base] ||= :url_safe
|
240
|
+
@options[:char_set] ||= nil
|
241
|
+
@options[:prefix] ||= nil
|
242
|
+
end
|
243
|
+
|
244
|
+
def get_check_config(key,conf)
|
245
|
+
raise ArgumentError, "config is not a Hash" unless conf.kind_of? Hash
|
246
|
+
raise ArgumentError, ":name cannot be nil for [#{key}]" if conf[:name].nil?
|
247
|
+
raise ArgumentError, ":options cannot be nil for [#{key}]" if conf[:options].nil?
|
248
|
+
if conf[:options].kind_of? Integer
|
249
|
+
conf[:size] = conf[:options]
|
250
|
+
elsif conf[:options].kind_of? Array
|
251
|
+
conf[:size] = conf[:options].size
|
252
|
+
elsif conf[:options].kind_of? Symbol || conf[:options].kind_of?(String)
|
253
|
+
raise ArgumentError, ":options Character set cannot have duplicate characters" if conf[:options].kind_of?(String) && (conf[:options].size != conf[:options].split(//).uniq.size)
|
254
|
+
raise ArgumentError, ":options"
|
255
|
+
raise ArgumentError, ":size needs to be an integer larger than 0 [#{conf[:name]}]" unless conf[:size].kind_of? Integer and conf[:size] > 0
|
256
|
+
else
|
257
|
+
raise ArgumentError, ":options needs to be an Array or Integer for [#{conf[:name]}]"
|
258
|
+
end
|
259
|
+
if !conf[:default].nil?
|
260
|
+
raise ArgumentError, "default value of (#{conf[:default]}) is not valid for #{conf[:name]}" unless check_value(conf,conf[:default])
|
261
|
+
default = conf[:default]
|
262
|
+
elsif !conf[:default_index].nil?
|
263
|
+
raise ArgumentError, ":default_index must be an integer #{conf[:name]}" unless conf[:default_index].kind_of? Integer
|
264
|
+
unless default = conf[:options][conf[:default_index]]
|
265
|
+
raise ArgumentError, ":default_index must be a valid option array index #{conf[:name]}"
|
266
|
+
end
|
267
|
+
end
|
268
|
+
conf[:size] = (conf[:size]-1).to_s(2).size
|
269
|
+
default ||= (conf[:options].kind_of? Integer) ? 0 : conf[:options][0]
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe BitHash do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@config_map = [
|
7
|
+
{ :name=> 'min_price_cents', :options => [1000000,1500000,2000000,3000000,3500000,4000000,4500000,5000000,5500000,6000000,6500000,7000000] },
|
8
|
+
{ :name=> 'max_price_cents', :options => [1500000,2000000,3000000,3500000,4000000,4500000,5000000,5500000,6000000,6500000,7000000,8000000] },
|
9
|
+
{ :name=> 'segment_1', :options => 2},
|
10
|
+
{ :name=> 'segment_2', :options => 2},
|
11
|
+
{ :name=> 'segment_3', :options => 2},
|
12
|
+
{ :name=> 'segment_4', :options => 2},
|
13
|
+
{ :name=> 'segment_5', :options => 2},
|
14
|
+
{ :name=> 'segment_6', :options => 2},
|
15
|
+
{ :name=> 'segment_7', :options => 2},
|
16
|
+
{ :name=> 'segment_8', :options => 2},
|
17
|
+
{ :name=> 'segment_9', :options => 2},
|
18
|
+
{ :name=> 'brand_pref_acura', :options => 3},
|
19
|
+
{ :name=> 'brand_pref_aston_martin', :options => 3},
|
20
|
+
{ :name=> 'brand_pref_audi', :options => 3},
|
21
|
+
{ :name=> 'brand_pref_bentley', :options => 3},
|
22
|
+
{ :name=> 'brand_pref_bmw', :options => 3},
|
23
|
+
{ :name=> 'brand_pref_buick', :options => 3},
|
24
|
+
{ :name=> 'brand_pref_cadillac', :options => 3},
|
25
|
+
{ :name=> 'brand_pref_chevrolet', :options => 3},
|
26
|
+
{ :name=> 'brand_pref_chrysler', :options => 3},
|
27
|
+
{ :name=> 'brand_pref_dodge', :options => 3},
|
28
|
+
{ :name=> 'brand_pref_ferrari', :options => 3},
|
29
|
+
{
|
30
|
+
:name => :air, # name of option
|
31
|
+
:options => 2, # number of options must be 2 or greater
|
32
|
+
},
|
33
|
+
{
|
34
|
+
:name => :color,
|
35
|
+
:options => ['blue','green','red'] # bit_hash can map arrays of data, the default setting will be the first value in the array
|
36
|
+
},
|
37
|
+
{
|
38
|
+
:name => :body_style,
|
39
|
+
:options => [:sedan,:mini_van,:suv], # Array values can be anything that can be found using the Array#index function
|
40
|
+
:default => :mini_van # for arrays the default is any array value
|
41
|
+
},
|
42
|
+
{
|
43
|
+
:name => :transmission, # name of option
|
44
|
+
:options => 6,
|
45
|
+
:default => 5 # for numbers the default must be between 0 and the options value
|
46
|
+
},
|
47
|
+
{
|
48
|
+
:name => :min_price,
|
49
|
+
:options => (50..100).to_a, # ( just a way to store ranges of numbers)
|
50
|
+
:default => 60 # basically any default can be used as long as it is a valid option
|
51
|
+
},
|
52
|
+
{
|
53
|
+
:name => :max_price,
|
54
|
+
# intervals of 20 starting at 10000 (just a way to store ranges of numbers)
|
55
|
+
:options => (1..5).to_a.map {|n| 10000+(n*20)},
|
56
|
+
# you can use :default_index option to reference something in the option arrays but it really isn't suggested, :default take precedence
|
57
|
+
:default_index => 2
|
58
|
+
}
|
59
|
+
]
|
60
|
+
@config = BitHash.new(@config_map)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should raise an error if config lacks name" do
|
64
|
+
BitHash.new(@config_map).should_not be_nil
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should raise an error if config lacks name" do
|
68
|
+
@config_map[0].delete(:name)
|
69
|
+
lambda { BitHash.new(@config_map) }.should raise_error(ArgumentError)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should be able to get keys" do
|
73
|
+
@config.keys.should be_a Array
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should have load same config" do
|
77
|
+
@config.parse(@config.to_s).should eql(@config.to_hash)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should output equal it self after being converted and parsed" do
|
81
|
+
str = @config.to_s
|
82
|
+
bin = @config.to_bin
|
83
|
+
@config.save(str)
|
84
|
+
bin.should eql(@config.to_bin)
|
85
|
+
end
|
86
|
+
|
87
|
+
it "settings should change" do
|
88
|
+
old = @config.to_s
|
89
|
+
@config.set!(:color,'red')
|
90
|
+
@config[:color].should eql('red')
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should have different string if settings change" do
|
94
|
+
@new = BitHash.new(@config_map)
|
95
|
+
@config[:color]= 'red'
|
96
|
+
@config[:body_style]= :suv
|
97
|
+
@config[:air]= 1
|
98
|
+
@new.save(@config.to_s)
|
99
|
+
@new[:body_style].should eql(:suv)
|
100
|
+
@new[:air].should eql(1)
|
101
|
+
@new[:color].should eql('red')
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'rspec'
|
4
|
+
require 'bit_hash'
|
5
|
+
|
6
|
+
# Requires supporting files with custom matchers and macros, etc,
|
7
|
+
# in ./support/ and its subdirectories.
|
8
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
|
12
|
+
end
|
metadata
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bit_hash
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ryan Ong
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-02-16 00:00:00 -05:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: to_insane
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.2.1
|
24
|
+
type: :runtime
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: shoulda
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: "0"
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: bundler
|
40
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.0.0
|
46
|
+
type: :development
|
47
|
+
prerelease: false
|
48
|
+
version_requirements: *id003
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: jeweler
|
51
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ~>
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 1.5.2
|
57
|
+
type: :development
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: *id004
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: rcov
|
62
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: "0"
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: *id005
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: rspec
|
73
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: "0"
|
79
|
+
type: :development
|
80
|
+
prerelease: false
|
81
|
+
version_requirements: *id006
|
82
|
+
description: bit_hash is a useful tool to pass through options through a string. The best usecases would be forms with binary,trinary, etc etc data sets.
|
83
|
+
email: ryanong@gmail.com
|
84
|
+
executables: []
|
85
|
+
|
86
|
+
extensions: []
|
87
|
+
|
88
|
+
extra_rdoc_files:
|
89
|
+
- LICENSE.txt
|
90
|
+
- README.rdoc
|
91
|
+
files:
|
92
|
+
- .document
|
93
|
+
- .rspec
|
94
|
+
- Gemfile
|
95
|
+
- Gemfile.lock
|
96
|
+
- LICENSE.txt
|
97
|
+
- README.rdoc
|
98
|
+
- Rakefile
|
99
|
+
- VERSION
|
100
|
+
- bit_hash.gemspec
|
101
|
+
- lib/bit_hash.rb
|
102
|
+
- spec/bit_hash_spec.rb
|
103
|
+
- spec/spec_helper.rb
|
104
|
+
has_rdoc: true
|
105
|
+
homepage: http://github.com/ryanong/bit_hash
|
106
|
+
licenses:
|
107
|
+
- MIT
|
108
|
+
post_install_message:
|
109
|
+
rdoc_options: []
|
110
|
+
|
111
|
+
require_paths:
|
112
|
+
- lib
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
hash: 59358543
|
119
|
+
segments:
|
120
|
+
- 0
|
121
|
+
version: "0"
|
122
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
124
|
+
requirements:
|
125
|
+
- - ">="
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: "0"
|
128
|
+
requirements: []
|
129
|
+
|
130
|
+
rubyforge_project:
|
131
|
+
rubygems_version: 1.5.0
|
132
|
+
signing_key:
|
133
|
+
specification_version: 3
|
134
|
+
summary: bit_hash allows you to serialize simple set data into short compact URL safe strings.
|
135
|
+
test_files:
|
136
|
+
- spec/bit_hash_spec.rb
|
137
|
+
- spec/spec_helper.rb
|