lorentz 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use --create --install maglev-26436@lorentz
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in lorentz.gemspec
4
+ gemspec
5
+
6
+ group :development, :test do
7
+ gem 'rspec'
8
+ end
data/README.md ADDED
@@ -0,0 +1,24 @@
1
+ # Lorentz
2
+
3
+ Redis on MagLev
4
+
5
+ ## Why?
6
+
7
+ Because it's \_why day, \_why day, gotta write a hack it's \_why day!
8
+
9
+ ## What's implemented so far?
10
+
11
+ * set
12
+ * get
13
+ * exists
14
+ * del
15
+ * keys (with glob pattern)
16
+ * rename
17
+ * renamenx
18
+ * strlen
19
+ * randomkey
20
+ * append
21
+
22
+ ## Inspiration
23
+
24
+ \_why of course! [Redis](http://redis.io) also. [ctoneal's strc](https://github.com/ctoneal/strc) is cool too but I want a real Redis within MagLev.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
data/lib/lorentz.rb ADDED
@@ -0,0 +1,38 @@
1
+ require "lorentz/version"
2
+ require "lorentz/exceptions"
3
+ require "lorentz/strings"
4
+ require "lorentz/keys"
5
+
6
+ class Lorentz
7
+
8
+ attr_reader :db
9
+ def initialize(opts={})
10
+ db_name = opts.delete(:db) || 0
11
+
12
+ @db = begin
13
+ ::Maglev::PERSISTENT_ROOT[:"lorentz_db_#{db_name}"] ||= {}
14
+ rescue
15
+ $stderr.puts "Maglev only"
16
+ exit
17
+ end
18
+ end
19
+ include Lorentz::Strings
20
+ include Lorentz::Keys
21
+
22
+ private
23
+ def save(&block)
24
+ begin
25
+ Maglev.abort_transaction
26
+ yield
27
+ Maglev.commit_transaction
28
+ rescue Maglev::CommitFailedException
29
+ $stderr.puts "I tried to save but I couldn't. Trying again."
30
+ redo
31
+ end
32
+ end
33
+
34
+ def run(&block)
35
+ Maglev.abort_transaction
36
+ yield
37
+ end
38
+ end
@@ -0,0 +1 @@
1
+ class LorentzException < StandardError; end
@@ -0,0 +1,32 @@
1
+ module Lorentz::Glob
2
+ # jacked from https://github.com/karottenreibe/joker
3
+ # & specifically http://karottenreibe.github.com/2009/12/03/inside-the-joker/
4
+ def compile(source, case_sensitive=false)
5
+ ptr = 0
6
+ compiled = '^'
7
+ while ptr < source.length
8
+ snip = source[ptr..ptr]
9
+ case snip
10
+ when '\\'
11
+ lookahead = source[ptr+1..ptr+1]
12
+ case snip
13
+ when '\\\\', '\\?', '\\*'
14
+ compiled << snip << lookahead
15
+ else
16
+ compiled << Regexp.quote(lookahead)
17
+ end
18
+ ptr += 1
19
+ when '?' then compiled << '.'
20
+ when '*' then compiled << '.*'
21
+ when '[' then compiled << '['
22
+ when ']' then compiled << ']'
23
+ else compiled << Regexp.quote(snip)
24
+ end
25
+ ptr += 1
26
+ end
27
+ compiled << '$'
28
+ Regexp.compile(compiled, case_sensitive)
29
+ end
30
+
31
+ module_function :compile
32
+ end
@@ -0,0 +1,53 @@
1
+ require 'lorentz/glob'
2
+
3
+ module Lorentz::Keys
4
+ include Lorentz::Glob
5
+
6
+ def exists(key)
7
+ run do
8
+ !!@db[key]
9
+ end
10
+ end
11
+
12
+ def del(*keys)
13
+ run do
14
+ keys.map{ |k| @db.delete(k) }.compact.size
15
+ end
16
+ end
17
+
18
+ def keys(pattern)
19
+ run do
20
+ @db.keys.grep(compile(pattern))
21
+ end
22
+ end
23
+
24
+ def rename(key, newkey)
25
+ if key == newkey
26
+ raise LorentzException, "newkey: #{newkey} must be different than key: #{key}"
27
+ end
28
+ raise LorentzException, "key: #{key} does not exist" unless exists(key)
29
+ save do
30
+ val = get(key)
31
+ del(key)
32
+ set(newkey, val)
33
+ end
34
+ end
35
+
36
+ def renamenx(key, newkey)
37
+ if key == newkey
38
+ raise LorentzException, "newkey: #{newkey} must be different than key: #{key}"
39
+ end
40
+ raise LorentzException, "key: #{key} does not exist" unless exists(key)
41
+ return 0 if exists(newkey)
42
+ rename(key, newkey)
43
+ return 1
44
+ end
45
+
46
+ def randomkey
47
+ return nil if @db.empty?
48
+ run do
49
+ @db.keys[rand(@db.keys.length)]
50
+ end
51
+ end
52
+
53
+ end
@@ -0,0 +1,40 @@
1
+ module Lorentz::Strings
2
+ def set(key, value)
3
+ save do
4
+ @db[key] = value
5
+ return "OK"
6
+ end
7
+ end
8
+
9
+ def get(key)
10
+ run do
11
+ @db[key]
12
+ end
13
+ end
14
+
15
+ def strlen(key)
16
+ val = get(key)
17
+ return 0 unless val
18
+ if val.kind_of?(String)
19
+ return val.length
20
+ else
21
+ raise LorentzException, "The value stored at key: #{key} is not a String"
22
+ end
23
+ end
24
+
25
+ def append(key, value)
26
+ if exists(key)
27
+ old_value = get(key)
28
+ if old_value.is_a?(String)
29
+ new_value = old_value << value
30
+ set(key, new_value)
31
+ return new_value.length
32
+ else
33
+ raise LorentzException, "The value stored at key: #{key} is not a String"
34
+ end
35
+ else
36
+ set(key, "")
37
+ return "OK"
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,7 @@
1
+ class Lorentz
2
+ class << self
3
+ def version
4
+ "0.0.1".freeze
5
+ end
6
+ end
7
+ end
data/lorentz.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "lorentz/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "lorentz"
7
+ s.version = Lorentz.version
8
+ s.authors = ["Jesse Cooke"]
9
+ s.email = ["jesse@jc00ke.com"]
10
+ s.homepage = "https://github.com/jc00ke/lorentz"
11
+ s.summary = %q{Take one Redis, stick it on MagLev}
12
+ s.description = %q{You know, for _why day!}
13
+ s.licenses = ['MIT']
14
+
15
+ s.rubyforge_project = "lorentz"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_development_dependency 'rspec', '~> 2.6.0'
23
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe Lorentz::Glob do
4
+ let(:wild) { Lorentz::Glob.compile('Fairy?ake*') }
5
+ let(:wildi) { Lorentz::Glob.compile('Fairy?ake*\?', true) }
6
+ let(:wildc) { Lorentz::Glob.compile('Fairy[cf]ake[!\\]]') }
7
+
8
+ it 'should match correct strings' do
9
+ wild.should match('Fairycake')
10
+ wild.should match('Fairyfakes')
11
+ wild.should match('Fairylake is a cool place')
12
+ end
13
+
14
+ it 'should not match incorrect strings' do
15
+ wild.should_not match('Dairycake')
16
+ wild.should_not match('Fairysteakes')
17
+ wild.should_not match('fairycake')
18
+ end
19
+
20
+ it 'should match case insensitive' do
21
+ wildi.should match('FairyCake?')
22
+ wildi.should match('fairyfakes?')
23
+ wildi.should match('FairyLake IS A COOL Place?')
24
+ end
25
+
26
+ it 'should know about character classes' do
27
+ wildc.should match('Fairycake!')
28
+ wildc.should match('Fairyfake]')
29
+ end
30
+ end
@@ -0,0 +1,183 @@
1
+ require 'spec_helper'
2
+
3
+ #EXPIRE
4
+ #EXPIREAT
5
+ #MOVE
6
+ #OBJECT
7
+ #PERSIST
8
+ #SORT
9
+ #TTL
10
+ #TYPE
11
+
12
+ describe "keys" do
13
+ let(:lorentz) { Lorentz.new }
14
+
15
+ describe "#exists" do
16
+ context "when key exists" do
17
+ it "should return true" do
18
+ lorentz.set("chunky", "bacon")
19
+ lorentz.exists("chunky").should be_true
20
+ end
21
+ end
22
+
23
+ context "when key doesn't exist" do
24
+ it "should return false" do
25
+ lorentz.exists("chunky").should be_false
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ describe "#del" do
32
+ before do
33
+ lorentz.set("chunky", 0)
34
+ lorentz.set("bacon", 1)
35
+ end
36
+ it "should delete keys that exist" do
37
+ lorentz.del("chunky", "bacon", "pet ham")
38
+ lorentz.exists("chunky").should be_false
39
+ lorentz.exists("bacon").should be_false
40
+ lorentz.exists("pet ham").should be_false
41
+ end
42
+
43
+ it "should return the number of deleted keys" do
44
+ lorentz.del("chunky", "bacon", "pet ham").should eq(2)
45
+ end
46
+ end
47
+
48
+ describe "#keys" do
49
+ before do
50
+ lorentz.set("chunky", 0)
51
+ lorentz.set("bacon", 1)
52
+ lorentz.set("chunked", 2)
53
+ lorentz.set("thunk", 3)
54
+ end
55
+
56
+ it "should match 'unk'" do
57
+ keys = lorentz.keys('*unk*')
58
+ keys.should have(3).items
59
+ %w(chunky chunked thunk).each do |k|
60
+ keys.should include(k)
61
+ end
62
+ end
63
+
64
+ it "should return all" do
65
+ keys = lorentz.keys('*')
66
+ keys.should have(4).items
67
+ %w(chunky chunked thunk bacon).each do |k|
68
+ keys.should include(k)
69
+ end
70
+ end
71
+ end
72
+
73
+ describe "#rename" do
74
+
75
+ context "when key exists" do
76
+
77
+ before do
78
+ lorentz.set("chunky", "bacon")
79
+ end
80
+
81
+ context "and newkey exists" do
82
+ before do
83
+ lorentz.set("yummy", "snacks")
84
+ end
85
+
86
+ it "should overwrite newkey" do
87
+ lorentz.rename("chunky", "yummy")
88
+ lorentz.get("yummy").should == "bacon"
89
+ end
90
+ end
91
+
92
+ context "and newkey doesn't exist" do
93
+ it "it should set new key" do
94
+ lorentz.rename("chunky", "yummy")
95
+ lorentz.get("yummy").should == "bacon"
96
+ end
97
+ end
98
+
99
+ context "and newkey is the same" do
100
+ it "should raise a LorentzException" do
101
+ expect do
102
+ lorentz.rename("chunky", "chunky")
103
+ end.to raise_error(LorentzException)
104
+ end
105
+ end
106
+
107
+ end
108
+
109
+ context "when key doesn't exist" do
110
+ it "should raise a LorentzException" do
111
+ expect do
112
+ lorentz.rename("chunky", "yummy")
113
+ end.to raise_error(LorentzException)
114
+ end
115
+
116
+ end
117
+ end
118
+
119
+ describe "renamenx" do
120
+
121
+ context "when key exists" do
122
+
123
+ before do
124
+ lorentz.set("chunky", "bacon")
125
+ end
126
+
127
+ context "and newkey exists" do
128
+ it "should return 0" do
129
+ lorentz.set("funky", "cold medina")
130
+ lorentz.renamenx("chunky", "funky").should be_zero
131
+ end
132
+ end
133
+
134
+ context "and newkey doesn't exist" do
135
+ it "should return 1" do
136
+ lorentz.renamenx("chunky", "funky").should eq(1)
137
+ end
138
+ end
139
+
140
+ context "and newkey is the same" do
141
+ it "should raise a LorentzException" do
142
+ expect do
143
+ lorentz.rename("chunky", "chunky")
144
+ end.to raise_error(LorentzException)
145
+ end
146
+ end
147
+ end
148
+
149
+ context "when key doesn't exist" do
150
+ it "should raise a LorentzException" do
151
+ expect do
152
+ lorentz.renamenx("chunky", "yummy")
153
+ end.to raise_error(LorentzException)
154
+ end
155
+
156
+ end
157
+ end
158
+
159
+ describe "randomkey" do
160
+ context "database with some keys" do
161
+ before do
162
+ 1.upto(1000){ |i| lorentz.set(i, i) }
163
+ end
164
+
165
+ it "should return a random key" do
166
+ (1..100).to_a.inject([]) do |memo, i|
167
+ memo << lorentz.randomkey
168
+ end.uniq.should have_at_least(90).keys
169
+ end
170
+ end
171
+
172
+ context "empty database" do
173
+ before do
174
+ # delete in case... paranoid much?
175
+ ::Maglev::PERSISTENT_ROOT.delete(:lorentz_db_100)
176
+ end
177
+ it "should return nil" do
178
+ l = Lorentz.new(:db => :lorentz_db_100)
179
+ l.randomkey.should be_nil
180
+ end
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,116 @@
1
+ require 'spec_helper'
2
+
3
+ #DECR
4
+ #DECRBY
5
+ #GETBIT
6
+ #GETRANGE
7
+ #GETSET
8
+ #INCR
9
+ #INCRBY
10
+ #MGET
11
+ #MSET
12
+ #MSETNX
13
+ #SETBIT
14
+ #SETEX
15
+ #SETNX
16
+ #SETRANGE
17
+
18
+ describe "strings" do
19
+ let(:lorentz) { Lorentz.new }
20
+
21
+ describe "#set" do
22
+ it "should set the key to the value" do
23
+ lorentz.set("chunky", 'bacon').should == "OK"
24
+ lorentz.db["chunky"].should eq("bacon")
25
+ end
26
+ end
27
+
28
+ describe "#setnx" do
29
+ context "when key exists" do
30
+ xit "should not set" do
31
+
32
+ end
33
+ end
34
+
35
+ context "when key doesn't exist" do
36
+ xit "should set" do
37
+
38
+ end
39
+ end
40
+ end
41
+
42
+ describe "#get" do
43
+ context "when key exists" do
44
+ it "should return the value" do
45
+ lorentz.set("chunky", "bacon")
46
+ lorentz.get("chunky").should == "bacon"
47
+ end
48
+ end
49
+ it "should return nil if key doesn't exist" do
50
+ lorentz.get("chunky").should be_nil
51
+ end
52
+ end
53
+
54
+ describe "#append" do
55
+ context "when key exists" do
56
+ context "and is a string" do
57
+ before do
58
+ lorentz.set("chunky", "bacon")
59
+ end
60
+ it "should tack value on to end of string" do
61
+ lorentz.append("chunky", " is yummy")
62
+ lorentz.get("chunky").should == "bacon is yummy"
63
+ end
64
+ it "should return length of value" do
65
+ lorentz.append("chunky", " is yummy").should eq("bacon is yummy".length)
66
+ end
67
+ end
68
+
69
+ context "and is not a string" do
70
+ before do
71
+ lorentz.set("chunky", 1)
72
+ end
73
+
74
+ it "should raise an error" do
75
+ expect do
76
+ lorentz.append("chunky", "bacon")
77
+ end.to raise_error(LorentzException)
78
+ end
79
+ end
80
+ end
81
+
82
+ context "when key doesn't exist" do
83
+ it "should return 'OK'" do
84
+ lorentz.append("chunky", "bacon").should == "OK"
85
+ end
86
+ it "should set the key to be an empty string" do
87
+ lorentz.append("chunky", "bacon")
88
+ lorentz.get("chunky").should be_empty
89
+ end
90
+ end
91
+ end
92
+
93
+ describe "#strlen" do
94
+ context "when key exists" do
95
+ before do
96
+ lorentz.set("chunky", "baconz")
97
+ lorentz.set("foo", ["bar"])
98
+ end
99
+ it "should return length of string value" do
100
+ lorentz.strlen("chunky").should eq(6)
101
+ end
102
+
103
+ it "should raise an error if value isn't a string" do
104
+ expect do
105
+ lorentz.strlen("foo")
106
+ end.to raise_error(LorentzException)
107
+ end
108
+ end
109
+
110
+ context "when key doesn't exist" do
111
+ it "should return 0" do
112
+ lorentz.strlen("chunky").should eq(0)
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe Lorentz do
4
+ context "default" do
5
+ its(:db) { should be_empty }
6
+ its(:db) { should be_a(Hash) }
7
+ end
8
+ end
@@ -0,0 +1,23 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ begin
5
+ Bundler.require(:default, :test)
6
+ rescue Bundler::BundlerError => e
7
+ $stderr.puts e.message
8
+ $stderr.puts "Run `bundle` to install missing gems"
9
+ exit e.status_code
10
+ end
11
+
12
+ require 'lorentz'
13
+ require 'rspec'
14
+
15
+ RSpec.configure do |config|
16
+ config.before(:each) do
17
+ ::Maglev.abort_transaction
18
+ ::Maglev::PERSISTENT_ROOT.delete_if do |key, val|
19
+ key.to_s =~ /^lorentz_db_.*$/
20
+ end
21
+ ::Maglev.commit_transaction
22
+ end
23
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lorentz
3
+ version: !ruby/object:Gem::Version
4
+ hash: 856480538658449761
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Jesse Cooke
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-08-23 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rspec
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 2489593565405618356
30
+ segments:
31
+ - 2
32
+ - 6
33
+ - 0
34
+ version: 2.6.0
35
+ type: :development
36
+ version_requirements: *id001
37
+ description: You know, for _why day!
38
+ email:
39
+ - jesse@jc00ke.com
40
+ executables: []
41
+
42
+ extensions: []
43
+
44
+ extra_rdoc_files: []
45
+
46
+ files:
47
+ - .gitignore
48
+ - .rvmrc
49
+ - Gemfile
50
+ - README.md
51
+ - Rakefile
52
+ - lib/lorentz.rb
53
+ - lib/lorentz/exceptions.rb
54
+ - lib/lorentz/glob.rb
55
+ - lib/lorentz/keys.rb
56
+ - lib/lorentz/strings.rb
57
+ - lib/lorentz/version.rb
58
+ - lorentz.gemspec
59
+ - spec/lorentz/glob_spec.rb
60
+ - spec/lorentz/keys_spec.rb
61
+ - spec/lorentz/strings_spec.rb
62
+ - spec/lorentz_spec.rb
63
+ - spec/spec_helper.rb
64
+ has_rdoc: true
65
+ homepage: https://github.com/jc00ke/lorentz
66
+ licenses:
67
+ - MIT
68
+ post_install_message:
69
+ rdoc_options: []
70
+
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ hash: 2002549777813010636
79
+ segments:
80
+ - 0
81
+ version: "0"
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ hash: 2002549777813010636
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ requirements: []
92
+
93
+ rubyforge_project: lorentz
94
+ rubygems_version: 1.5.2
95
+ signing_key:
96
+ specification_version: 3
97
+ summary: Take one Redis, stick it on MagLev
98
+ test_files: []
99
+