symboltable 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,81 @@
1
+ +++ SymbolTable +++
2
+
3
+ SymbolTable is a handy little Ruby class that was conceived from the union of
4
+ Hash and Symbol. SymbolTable directly extends Hash, but it stores all keys
5
+ internally as symbols. Any key that cannot be converted to a Symbol is not
6
+ valid.
7
+
8
+ While this may seem restrictive, it does have the nice side effect of making
9
+ all keys slightly more memorable and usable. For example, values may be set
10
+ and retrieved using any key that resolves to the same symbol.
11
+
12
+ h = Hash.new
13
+ h[:a] = 1
14
+ h[:a] # => 1
15
+ h['a'] # => nil
16
+ h.a # => NoMethodError: undefined method `a' for {}:Hash
17
+
18
+ require 'symboltable'
19
+
20
+ t = SymbolTable.new
21
+ t[:a] = 1
22
+ t[:a] # => 1
23
+ t['a'] # => 1
24
+ t.a # => 1
25
+ t.b = 2 # => 2
26
+
27
+ Also, because SymbolTable subclasses Hash, you get all the nice methods of Hash
28
+ for free.
29
+
30
+ t.keys # => [:a, :b]
31
+ t.values # => [1, 2]
32
+
33
+ t.merge!('c' => 3, :d => 4)
34
+ t.keys # => [:a, :b, :c, :d]
35
+ t.values # => [1, 2, 3, 4]
36
+
37
+ t.each do |k, v|
38
+ puts "#{k} = #{v}"
39
+ end
40
+
41
+ You get the idea. This kind of data structure is mainly useful for large
42
+ configuration objects and the like, where you want to store a bunch of data and
43
+ you don't want to have to remember later how you stored it.
44
+
45
+ == Why?
46
+
47
+ Mainly just for fun, and because I sometimes miss the automatic and ubiquitous
48
+ type conversion you get in PHP.
49
+
50
+ == Installation
51
+
52
+ Using RubyGems:
53
+
54
+ $ sudo gem install symboltable
55
+
56
+ From a local copy:
57
+
58
+ $ git clone git://github.com/mjijackson/symboltable.git
59
+ $ rake package && sudo rake install
60
+
61
+ == License
62
+
63
+ Copyright 2010 Michael J. I. Jackson
64
+
65
+ Permission is hereby granted, free of charge, to any person obtaining a copy
66
+ of this software and associated documentation files (the "Software"), to deal
67
+ in the Software without restriction, including without limitation the rights
68
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
69
+ copies of the Software, and to permit persons to whom the Software is
70
+ furnished to do so, subject to the following conditions:
71
+
72
+ The above copyright notice and this permission notice shall be included in
73
+ all copies or substantial portions of the Software.
74
+
75
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
76
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
77
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
78
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
79
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
80
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
81
+ THE SOFTWARE.
@@ -0,0 +1,67 @@
1
+ require 'rake/clean'
2
+ require 'rake/testtask'
3
+
4
+ task :default => :test
5
+
6
+ CLEAN.include %w< doc >
7
+ CLOBBER.include %w< dist >
8
+
9
+ # TESTS #######################################################################
10
+
11
+ Rake::TestTask.new(:test) do |t|
12
+ t.test_files = FileList['test/symboltable.rb']
13
+ end
14
+
15
+ # DOCS ########################################################################
16
+
17
+ desc "Generate API documentation (in doc)"
18
+ task :doc => FileList['lib/**/*.rb'] do |t|
19
+ rm_rf 'doc'
20
+ sh((<<-SH).gsub(/[\s\n]+/, ' ').strip)
21
+ hanna
22
+ --op doc
23
+ --promiscuous
24
+ --charset utf8
25
+ --fmt html
26
+ --inline-source
27
+ --line-numbers
28
+ --accessor option_accessor=RW
29
+ --main SymbolTable
30
+ --title 'SymbolTable API Documentation'
31
+ #{t.prerequisites.join(' ')}
32
+ SH
33
+ end
34
+
35
+ # PACKAGING & INSTALLATION ####################################################
36
+
37
+ if defined?(Gem)
38
+ $spec = eval("#{File.read('symboltable.gemspec')}")
39
+
40
+ directory 'dist'
41
+
42
+ def package(ext='')
43
+ "dist/#{$spec.name}-#{$spec.version}" + ext
44
+ end
45
+
46
+ file package('.gem') => %w< dist > + $spec.files do |f|
47
+ sh "gem build symboltable.gemspec"
48
+ mv File.basename(f.name), f.name
49
+ end
50
+
51
+ file package('.tar.gz') => %w< dist > + $spec.files do |f|
52
+ sh "git archive --format=tar HEAD | gzip > #{f.name}"
53
+ end
54
+
55
+ desc "Build packages"
56
+ task :package => %w< .gem .tar.gz >.map {|e| package(e) }
57
+
58
+ desc "Build and install as local gem"
59
+ task :install => package('.gem') do |t|
60
+ sh "gem install #{package('.gem')}"
61
+ end
62
+
63
+ desc "Upload gem to rubygems.org"
64
+ task :release => package('.gem') do |t|
65
+ sh "gem push #{package('.gem')}"
66
+ end
67
+ end
@@ -0,0 +1,54 @@
1
+ # A Hash that forces all keys to be symbols.
2
+ #
3
+ # See http://github.com/mjijackson/symboltable for more information.
4
+ class SymbolTable < Hash
5
+
6
+ def initialize(hash=nil)
7
+ super()
8
+ merge!(hash) unless hash.nil?
9
+ end
10
+
11
+ # Returns +true+ if the given key may be used in this table.
12
+ def valid_key?(key)
13
+ key.respond_to?(:to_sym)
14
+ end
15
+
16
+ def key?(key)
17
+ super(key) || (valid_key?(key) && super(key.to_sym))
18
+ end
19
+
20
+ def [](key)
21
+ super(key.to_sym) if valid_key?(key)
22
+ end
23
+
24
+ def store(key, val)
25
+ if valid_key?(key)
26
+ val = SymbolTable.new(val) if Hash === val && !(SymbolTable === val)
27
+ super(key.to_sym, val)
28
+ end
29
+ end
30
+ alias :[]= :store
31
+
32
+ def merge!(other_hash)
33
+ raise ArgumentError unless Hash === other_hash
34
+ other_hash.each do |k, v|
35
+ if block_given? && key?(k)
36
+ self[k] = yield(k, self[k], v)
37
+ else
38
+ self[k] = v
39
+ end
40
+ end
41
+ end
42
+ alias :update :merge!
43
+
44
+ def method_missing(sym, *args)
45
+ if sym.to_s =~ /(.+)=$/
46
+ self[$1] = args[0]
47
+ elsif args.empty?
48
+ self[sym]
49
+ else
50
+ super(sym, *args)
51
+ end
52
+ end
53
+
54
+ end
@@ -0,0 +1,27 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'symboltable'
3
+ s.version = '0.1'
4
+ s.date = '2010-04-08'
5
+
6
+ s.summary = 'A Symbols-only Hash for Ruby'
7
+ s.description = 'A Symbols-only Hash for Ruby'
8
+
9
+ s.author = 'Michael J. I. Jackson'
10
+ s.email = 'mjijackson@gmail.com'
11
+
12
+ s.require_paths = %w< lib >
13
+
14
+ s.files = Dir['lib/**/*.rb'] +
15
+ Dir['test/*.rb'] +
16
+ %w< symboltable.gemspec Rakefile README >
17
+
18
+ s.test_files = s.files.select {|path| path =~ /^test\/.*.rb/ }
19
+
20
+ s.add_development_dependency('rake')
21
+
22
+ s.has_rdoc = true
23
+ s.rdoc_options = %w< --line-numbers --inline-source --title SymbolTable --main SymbolTable >
24
+ s.extra_rdoc_files = %w< README >
25
+
26
+ s.homepage = 'http://github.com/mjijackson/symboltable'
27
+ end
@@ -0,0 +1,126 @@
1
+ libdir = File.dirname(File.dirname(__FILE__)) + '/lib'
2
+ $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
3
+
4
+ require 'test/unit'
5
+ require 'symboltable'
6
+
7
+ class SymbolTableTest < Test::Unit::TestCase
8
+
9
+ def test_empty
10
+ t = SymbolTable.new
11
+
12
+ assert_equal(nil, t[:a])
13
+ assert_equal(nil, t['a'])
14
+ end
15
+
16
+ def test_bracket
17
+ t = SymbolTable.new
18
+
19
+ t[:a] = 1
20
+ assert_equal(1, t[:a])
21
+ assert_equal(1, t['a'])
22
+
23
+ t['b'] = 1
24
+ assert_equal(1, t[:b])
25
+ assert_equal(1, t['b'])
26
+
27
+ assert_equal([:a, :b], t.keys)
28
+ assert_equal([1, 1], t.values)
29
+ end
30
+
31
+ def test_store
32
+ t = SymbolTable.new
33
+
34
+ t.store(:a, 1)
35
+ assert_equal(1, t[:a])
36
+ assert_equal(1, t['a'])
37
+
38
+ t.store('b', 1)
39
+ assert_equal(1, t[:b])
40
+ assert_equal(1, t['b'])
41
+
42
+ assert_equal([:a, :b], t.keys)
43
+ assert_equal([1, 1], t.values)
44
+ end
45
+
46
+ def test_update
47
+ t = SymbolTable.new
48
+
49
+ t.update(:a => 1)
50
+ assert_equal(1, t[:a])
51
+ assert_equal(1, t['a'])
52
+
53
+ t.update('b' => 1)
54
+ assert_equal(1, t[:b])
55
+ assert_equal(1, t['b'])
56
+
57
+ assert_equal([:a, :b], t.keys)
58
+ assert_equal([1, 1], t.values)
59
+ end
60
+
61
+ def test_merge!
62
+ t = SymbolTable.new
63
+
64
+ t.merge!(:a => 1)
65
+ assert_equal(1, t[:a])
66
+ assert_equal(1, t['a'])
67
+
68
+ t.merge!('b' => 1)
69
+ assert_equal(1, t[:b])
70
+ assert_equal(1, t['b'])
71
+
72
+ assert_equal([:a, :b], t.keys)
73
+ assert_equal([1, 1], t.values)
74
+ end
75
+
76
+ def test_method_missing
77
+ t = SymbolTable.new
78
+
79
+ t.a = 1
80
+ assert_equal(1, t[:a])
81
+ assert_equal(1, t['a'])
82
+ assert_equal(1, t.a)
83
+
84
+ assert_equal([:a], t.keys)
85
+ assert_equal([1], t.values)
86
+ end
87
+
88
+ def test_nested_tables
89
+ t = SymbolTable.new
90
+
91
+ t[:a] = {:a => 1}
92
+ assert_equal(1, t.a[:a])
93
+ assert_equal(1, t.a['a'])
94
+
95
+ t[:a] = {'a' => 1}
96
+ assert_equal(1, t.a[:a])
97
+ assert_equal(1, t.a['a'])
98
+ end
99
+
100
+ def test_key?
101
+ t = SymbolTable.new
102
+
103
+ t[:a] = 1
104
+ assert(t.key?(:a))
105
+ assert(t.key?('a'))
106
+ end
107
+
108
+ def test_new
109
+ t = SymbolTable[:a, 1]
110
+
111
+ assert_equal(1, t[:a])
112
+ assert_equal(1, t['a'])
113
+ end
114
+
115
+ def test_merge
116
+ t = SymbolTable.new
117
+ t[:a] = 1
118
+ b = t.merge(:a => 2)
119
+
120
+ assert_equal([:a], t.keys)
121
+ assert_equal([1], t.values)
122
+ assert_equal([:a], b.keys)
123
+ assert_equal([2], b.values)
124
+ end
125
+
126
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: symboltable
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ version: "0.1"
9
+ platform: ruby
10
+ authors:
11
+ - Michael J. I. Jackson
12
+ autorequire:
13
+ bindir: bin
14
+ cert_chain: []
15
+
16
+ date: 2010-04-08 00:00:00 -06:00
17
+ default_executable:
18
+ dependencies:
19
+ - !ruby/object:Gem::Dependency
20
+ name: rake
21
+ prerelease: false
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ segments:
27
+ - 0
28
+ version: "0"
29
+ type: :development
30
+ version_requirements: *id001
31
+ description: A Symbols-only Hash for Ruby
32
+ email: mjijackson@gmail.com
33
+ executables: []
34
+
35
+ extensions: []
36
+
37
+ extra_rdoc_files:
38
+ - README
39
+ files:
40
+ - lib/symboltable.rb
41
+ - test/symboltable.rb
42
+ - symboltable.gemspec
43
+ - Rakefile
44
+ - README
45
+ has_rdoc: true
46
+ homepage: http://github.com/mjijackson/symboltable
47
+ licenses: []
48
+
49
+ post_install_message:
50
+ rdoc_options:
51
+ - --line-numbers
52
+ - --inline-source
53
+ - --title
54
+ - SymbolTable
55
+ - --main
56
+ - SymbolTable
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ requirements: []
74
+
75
+ rubyforge_project:
76
+ rubygems_version: 1.3.6
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: A Symbols-only Hash for Ruby
80
+ test_files:
81
+ - test/symboltable.rb