toad_spawn 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ sandbox
data/.rvmrc ADDED
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # This is an RVM Project .rvmrc file, used to automatically load the ruby
4
+ # development environment upon cd'ing into the directory
5
+
6
+ # First we specify our desired <ruby>[@<gemset>], the @gemset name is optional,
7
+ # Only full ruby name is supported here, for short names use:
8
+ # echo "rvm use 1.8.7" > .rvmrc
9
+ environment_id="ruby-1.8.7-p370@toad_spawn"
10
+
11
+ # Uncomment the following lines if you want to verify rvm version per project
12
+ # rvmrc_rvm_version="1.15.8 (stable)" # 1.10.1 seams as a safe start
13
+ # eval "$(echo ${rvm_version}.${rvmrc_rvm_version} | awk -F. '{print "[[ "$1*65536+$2*256+$3" -ge "$4*65536+$5*256+$6" ]]"}' )" || {
14
+ # echo "This .rvmrc file requires at least RVM ${rvmrc_rvm_version}, aborting loading."
15
+ # return 1
16
+ # }
17
+
18
+ # First we attempt to load the desired environment directly from the environment
19
+ # file. This is very fast and efficient compared to running through the entire
20
+ # CLI and selector. If you want feedback on which environment was used then
21
+ # insert the word 'use' after --create as this triggers verbose mode.
22
+ if [[ -d "${rvm_path:-$HOME/.rvm}/environments"
23
+ && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
24
+ then
25
+ \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
26
+ [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]] &&
27
+ \. "${rvm_path:-$HOME/.rvm}/hooks/after_use" || true
28
+ else
29
+ # If the environment file has not yet been created, use the RVM CLI to select.
30
+ rvm --create "$environment_id" || {
31
+ echo "Failed to create RVM environment '${environment_id}'."
32
+ return 1
33
+ }
34
+ fi
35
+
36
+ # If you use bundler, this might be useful to you:
37
+ # if [[ -s Gemfile ]] && {
38
+ # ! builtin command -v bundle >/dev/null ||
39
+ # builtin command -v bundle | GREP_OPTIONS= \grep $rvm_path/bin/bundle >/dev/null
40
+ # }
41
+ # then
42
+ # printf "%b" "The rubygem 'bundler' is not installed. Installing it now.\n"
43
+ # gem install bundler
44
+ # fi
45
+ # if [[ -s Gemfile ]] && builtin command -v bundle >/dev/null
46
+ # then
47
+ # bundle install | GREP_OPTIONS= \grep -vE '^Using|Your bundle is complete'
48
+ # fi
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'http://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in toad_spawn.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Andy White
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,75 @@
1
+ # ToadSpawn
2
+
3
+ A basic persistent hash. Behaves similar to a normal hash but the key value
4
+ pairs persist between instantiations. The keys must be symbols and only
5
+ strings, floats and fixnums can be stored as their original types, anything
6
+ else is converted to a string. A simple file based store is used under the
7
+ hood.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'toad_spawn'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install toad_spawn
22
+
23
+ ## Usage
24
+
25
+ Say you want a simple key/value based persistent data store:
26
+
27
+ whatever = ToadSpawn::Base.new('/path/folder/A')
28
+
29
+ The path argument must be an existing, writable folder and gives the ToadSpawn
30
+ it's uniqueness. If you instantiate ToadSpawn with this path anywhere again,
31
+ it will have the same data.
32
+
33
+ So later, or in another program:
34
+
35
+ data = ToadSpawn::Base.new('/path/folder/A')
36
+
37
+ data[:string] = 'ant'
38
+ data[:float] = 1.2345
39
+ data[:fixnum] = 1001
40
+
41
+ data[:string] # => 'ant'
42
+ data[:float] # => 1.2345
43
+ data[:fixnum] # => 1001
44
+
45
+ another_spawn = ToadSpawn::Base.new('/path/folder/B')
46
+ another_spawn.size # => 0
47
+
48
+ These methods work just like in Hash:
49
+
50
+ data.to_hash # => {:string => 'ant', :float => 1.2345, :fixnum => 1001}
51
+ data.empty? # => false
52
+ data.any? # => true
53
+ data.has_key?(:float) # => true
54
+ data.has_value?(100) # => false
55
+ data.keys # => [:string, :float, :fixnum]
56
+ data.values # => ['ant', 1.2345, 1001]
57
+ data.size # => 3
58
+ data.delete(:float) # => deletes the value and returns it: 1.2345
59
+ data.clear # => clears the ToadSpawn and returns {}
60
+
61
+ ### Don't forget to flush!
62
+
63
+ Because ToadSpawn uses caching under the hood to improve performance, please
64
+ be aware that it is not automatically mutiprocess safe - meaning that if a spawn is
65
+ instantiated and another process opens the same spawn and changes an element,
66
+ that change will not be seen by the original spawn - until it is
67
+ re-instantiated or the *flush* method is called to re-read the filesystem.
68
+
69
+ ## Contributing
70
+
71
+ 1. Fork it
72
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
73
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
74
+ 4. Push to the branch (`git push origin my-new-feature`)
75
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1 @@
1
+ a file
@@ -0,0 +1,28 @@
1
+ TravelBloggers Unite ‏@tbloggersunite
2
+ That awkward moment when Fábio Coentrão spoils a perfectly good photo #TBUPOR
3
+ Expand
4
+ Reply Retweet Favorite Buffer
5
+ 2h Paul Ricketts ‏@sifu33
6
+ I liked a @YouTube video from @kungfujack1 http://youtu.be/3P6xk1xZXyA?a KungFuJack Goes For A Stroll
7
+ View media
8
+ Reply Retweet Favorite Buffer
9
+ 2h Jayne Gorman ‏@jayneytravels
10
+ And I won the business card draw (again!) Framed photo of @Melbourne street art is mine! #greatjourneys
11
+ Expand
12
+ Reply Retweet Favorite Buffer
13
+ 2h Mike Phillips ‏@mcphillips
14
+ RT @GFQNetwork: What the Tech is live at 4pm ET W/ Paul @thurrott and @andrewzarian. Watch and chat with us http://www.gfqlive.tv
15
+ Expand
16
+ Reply Retweet Favorite Buffer
17
+ 2h Keith Fowler ‏@Keith_Fowler
18
+ Seeing the Ukelele Orchestra of Great Britain @Worthingtheaters Yay!
19
+ Expand
20
+ Reply Retweet Favorite Buffer
21
+ 9h Jane Hames ‏@glidetraining
22
+ Just 12 spaces left for @mumpre
23
+ ==============
24
+
25
+ Element Reference—If passed a single Fixnum, returns the code of the character at that position. If passed two Fixnum objects, returns a substring starting at the offset given by the first, and a length given by the second. If given a range, a substring containing characters at offsets given by the range is returned. In all three cases, if an offset is negative, it is counted from the end of str. Returns nil if the initial offset falls outside the string, the length is negative, or the beginning of the range is greater than the end.
26
+
27
+ If a Regexp is supplied, the matching portion of str is returned. If a numeric parameter follows the regular expression, that component of the MatchData is returned instead. If a String is given, that string is returned if it occurs in str. In both cases, nil is returned if there is no match.
28
+
@@ -0,0 +1,3 @@
1
+ require "toad_spawn/version"
2
+ require "toad_spawn/base"
3
+
@@ -0,0 +1,106 @@
1
+ module ToadSpawn
2
+ class Base
3
+ def initialize(path)
4
+ raise "Directory does not exist" unless File.exist?(path)
5
+ raise "Not a directory" unless File.directory?(path)
6
+ raise "Not writable" unless File.writable?(path)
7
+ @path = path
8
+ flush
9
+ end
10
+
11
+ def key_file_path(key)
12
+ File.join(@path, key.to_s + ".value")
13
+ end
14
+
15
+ def format(key, value)
16
+ "#{value.class}\n#{value}"
17
+ end
18
+
19
+ def klass(data)
20
+ data[/^(.+)\n/,1]
21
+ end
22
+
23
+ def value(data)
24
+ data.sub(/^.+\n/,'')
25
+ end
26
+
27
+ def cast(value, klass)
28
+ case klass
29
+ when 'Fixnum'
30
+ value.to_i
31
+ when 'Float'
32
+ value.to_f
33
+ else
34
+ value.to_s
35
+ end
36
+ end
37
+
38
+ def []=(key, value)
39
+ File.open(key_file_path(key), "w") do |f|
40
+ f.write format(key, value)
41
+ end
42
+ @cache[key] = cast(value, value.class.to_s)
43
+ end
44
+
45
+ def read_file(path)
46
+ data = File.read(path)
47
+ [File.basename(path, ".value").to_sym, cast(value(data), klass(data))]
48
+ end
49
+
50
+ def [](key)
51
+ @cache[key]
52
+ end
53
+
54
+ def flush
55
+ @cache = {}
56
+ Dir.glob("#{@path}/*.value").each do |path|
57
+ key, value = read_file(path)
58
+ @cache[key] = value
59
+ end
60
+ end
61
+
62
+ def to_hash
63
+ @cache
64
+ end
65
+
66
+ def any?
67
+ @cache.any?
68
+ end
69
+
70
+ def empty?
71
+ @cache.empty?
72
+ end
73
+
74
+ def delete(key)
75
+ File.delete key_file_path(key)
76
+ @cache.delete(key)
77
+ end
78
+
79
+ def has_key?(key)
80
+ @cache.has_key?(key)
81
+ end
82
+
83
+ def has_value?(value)
84
+ @cache.has_value?(value)
85
+ end
86
+
87
+ def keys
88
+ @cache.keys
89
+ end
90
+
91
+ def values
92
+ @cache.values
93
+ end
94
+
95
+ def size
96
+ @cache.size
97
+ end
98
+
99
+ def clear
100
+ Dir.glob("#{@path}/*.value").each do |path|
101
+ File.delete(path)
102
+ end
103
+ @cache = {}
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,3 @@
1
+ module ToadSpawn
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,14 @@
1
+ def fixtures(path = nil)
2
+ fixtures_path = File.join(File.dirname(__FILE__), '..', 'fixtures')
3
+ path.nil? ? fixtures_path : File.join(fixtures_path, path)
4
+ end
5
+
6
+ def sandbox(path = nil)
7
+ sandbox_path = File.join(File.dirname(__FILE__), '..', 'sandbox')
8
+ path.nil? ? sandbox_path : File.join(sandbox_path, path)
9
+ end
10
+
11
+ def reset_sandbox
12
+ system "rm -fr #{sandbox}"
13
+ system "mkdir #{sandbox}"
14
+ end
@@ -0,0 +1,201 @@
1
+ require 'toad_spawn/base'
2
+ require File.dirname(__FILE__) + '/helper'
3
+
4
+ describe ToadSpawn::Base do
5
+ before(:each) do
6
+ reset_sandbox
7
+ end
8
+
9
+ describe "Path validation" do
10
+ it "Raise error if directory absent" do
11
+ lambda { ToadSpawn::Base.new('does/not/exist') } .should raise_error 'Directory does not exist'
12
+ end
13
+
14
+ it "Raise error if not a directory" do
15
+ lambda { ToadSpawn::Base.new(fixtures('afile.txt')) } .should raise_error 'Not a directory'
16
+ end
17
+
18
+ it "Raise error if not writable" do
19
+ lambda { ToadSpawn::Base.new('/bin') } .should raise_error 'Not writable'
20
+ end
21
+ end
22
+
23
+ describe "Setting and reading data" do
24
+ before(:each) do
25
+ @db_folder = sandbox('spawn')
26
+ system "mkdir #{@db_folder}"
27
+ @data = ToadSpawn::Base.new(@db_folder)
28
+ end
29
+
30
+ it "#key_file_path" do
31
+ @data.key_file_path(:foobar).should == File.join(@db_folder, 'foobar.value')
32
+ end
33
+
34
+ it "returns nil if key does not exist" do
35
+ @data[:aardvarks] == nil
36
+ end
37
+
38
+ it "set and read string" do
39
+ @data[:foo] = 'bar'
40
+ @data[:foo].should == 'bar'
41
+ end
42
+
43
+ it "set and read complex string" do
44
+ @data[:long] = File.read(fixtures('long.txt'))
45
+ @data[:long].should == File.read(fixtures('long.txt'))
46
+ end
47
+
48
+ it "set and read Fixnum" do
49
+ @data[:fixnum] = 1001
50
+ @data[:fixnum].should == 1001
51
+ end
52
+
53
+ it "set and read Float" do
54
+ @data[:fixnum] = 1.2345
55
+ @data[:fixnum].should == 1.2345
56
+ end
57
+ end
58
+
59
+ describe "Persistence" do
60
+ before(:each) do
61
+ @folder = sandbox
62
+ @first = ToadSpawn::Base.new(@folder)
63
+ @first[:foo] = 'bam'
64
+ @first[:bar] = 22.2
65
+ end
66
+
67
+ it "second should be same data as first" do
68
+ second = ToadSpawn::Base.new(@folder)
69
+ second[:foo].should == 'bam'
70
+ second[:bar].should == 22.2
71
+ end
72
+
73
+ it "changes in first should be reflected in second" do
74
+ @first.delete(:foo)
75
+ second = ToadSpawn::Base.new(@folder)
76
+ second[:foo].should == nil
77
+ end
78
+
79
+ describe "flushing" do
80
+ it "should see same data when flushed" do
81
+ second = ToadSpawn::Base.new(@folder)
82
+ second.size.should == 2
83
+ @first.delete(:foo)
84
+ second.size.should == 2
85
+ second.flush
86
+ second.size.should == 1
87
+ end
88
+ end
89
+ end
90
+
91
+ describe "Data functions" do
92
+ before(:each) do
93
+ reset_sandbox
94
+ @folder1 = sandbox('1')
95
+ @folder2 = sandbox('2')
96
+ Dir.mkdir @folder1
97
+ Dir.mkdir @folder2
98
+ @data = ToadSpawn::Base.new(@folder1)
99
+ @data[:one] = 'a'
100
+ @data[:two] = 2
101
+ @data[:three] = 0.3
102
+ end
103
+
104
+ describe "#to_hash" do
105
+ it "should return a hash" do
106
+ @data.to_hash.should == {:one => 'a', :two => 2, :three => 0.3}
107
+ end
108
+ end
109
+
110
+ describe "#empty?" do
111
+ it "should deem it empty" do
112
+ ToadSpawn::Base.new(@folder2).empty?.should be_true
113
+ end
114
+
115
+ it "should deem it not empty" do
116
+ @data.empty?.should be_false
117
+ end
118
+ end
119
+
120
+ describe "#any?" do
121
+ it "should deem it empty" do
122
+ ToadSpawn::Base.new(@folder2).any?.should be_false
123
+ end
124
+
125
+ it "should deem it not empty" do
126
+ @data.any?.should be_true
127
+ end
128
+ end
129
+
130
+ describe "#has_key?" do
131
+ it "should find the key" do
132
+ @data.has_key?(:three).should be_true
133
+ end
134
+
135
+ it "should not find the key" do
136
+ @data.has_key?(:boomerangs).should be_false
137
+ end
138
+ end
139
+
140
+ describe "#has_value?" do
141
+ it "should find the value" do
142
+ @data.has_value?(2).should be_true
143
+ end
144
+
145
+ it "should not find the value" do
146
+ @data.has_value?('some aardvarks').should be_false
147
+ end
148
+ end
149
+
150
+ describe "#keys" do
151
+ it "should return keys as array" do
152
+ keys = @data.keys
153
+ keys.class.should == Array
154
+ keys.size.should == 3
155
+ keys.include?(:one).should be_true
156
+ keys.include?(:two).should be_true
157
+ keys.include?(:three).should be_true
158
+ end
159
+ end
160
+
161
+ describe "#values" do
162
+ it "should return values as array" do
163
+ vals = @data.values
164
+ vals.class.should == Array
165
+ vals.size.should == 3
166
+ vals.include?('a').should be_true
167
+ vals.include?(2).should be_true
168
+ vals.include?(0.3).should be_true
169
+ end
170
+ end
171
+
172
+ describe "#size" do
173
+ it "should measure a full" do
174
+ @data.size.should == 3
175
+ end
176
+
177
+ it "should measure a zero" do
178
+ ToadSpawn::Base.new(@folder2).size.should == 0
179
+ end
180
+ end
181
+
182
+ describe "#delete" do
183
+ it "should delete an element" do
184
+ @data.delete(:three)
185
+ @data[:three].should be_nil
186
+ @data.size.should == 2
187
+ end
188
+
189
+ it "should return deleted element" do
190
+ @data.delete(:two).should == 2
191
+ end
192
+ end
193
+
194
+ describe "#clear" do
195
+ it "should delete all elements" do
196
+ @data.clear
197
+ @data.size.should == 0
198
+ end
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'toad_spawn/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "toad_spawn"
8
+ s.version = ToadSpawn::VERSION
9
+ s.authors = ["Andy White"]
10
+ s.email = ["andy@wireworldmedia.co.uk"]
11
+ s.description = %q{A persistant, file based hash}
12
+ s.summary = %q{A basic persistent hash. Behaves similar to a normal hash but the key value
13
+ pairs persist between instantiations. The keys must be symbols and only
14
+ strings, floats and fixnums can be stored as their original types, anything
15
+ else is converted to a string. A simple file based store is used under the
16
+ hood.}
17
+ s.homepage = ""
18
+
19
+ s.files = `git ls-files`.split($/)
20
+ s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
21
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
22
+ s.require_paths = ["lib"]
23
+ s.add_development_dependency "rspec", "~> 2.11.0"
24
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: toad_spawn
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Andy White
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-09-12 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ hash: 35
29
+ segments:
30
+ - 2
31
+ - 11
32
+ - 0
33
+ version: 2.11.0
34
+ type: :development
35
+ version_requirements: *id001
36
+ description: A persistant, file based hash
37
+ email:
38
+ - andy@wireworldmedia.co.uk
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files: []
44
+
45
+ files:
46
+ - .gitignore
47
+ - .rvmrc
48
+ - Gemfile
49
+ - LICENSE.txt
50
+ - README.md
51
+ - Rakefile
52
+ - fixtures/afile.txt
53
+ - fixtures/long.txt
54
+ - lib/toad_spawn.rb
55
+ - lib/toad_spawn/base.rb
56
+ - lib/toad_spawn/version.rb
57
+ - spec/helper.rb
58
+ - spec/toad_spawn_spec.rb
59
+ - toad_spawn.gemspec
60
+ homepage: ""
61
+ licenses: []
62
+
63
+ post_install_message:
64
+ rdoc_options: []
65
+
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ hash: 3
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ hash: 3
83
+ segments:
84
+ - 0
85
+ version: "0"
86
+ requirements: []
87
+
88
+ rubyforge_project:
89
+ rubygems_version: 1.8.24
90
+ signing_key:
91
+ specification_version: 3
92
+ summary: A basic persistent hash. Behaves similar to a normal hash but the key value pairs persist between instantiations. The keys must be symbols and only strings, floats and fixnums can be stored as their original types, anything else is converted to a string. A simple file based store is used under the hood.
93
+ test_files:
94
+ - spec/helper.rb
95
+ - spec/toad_spawn_spec.rb