gaga 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ .rvmrc
4
+ Gemfile.lock
5
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in gaga.gemspec
4
+ gemspec
@@ -0,0 +1,43 @@
1
+ Gaga
2
+ ==========
3
+
4
+ Git as a key-value store! Build with [Grit](https://github.com/mojombo/grit), it supports SET, GET, KEYS, and DELETE operations. In addition, we can also get the change history key/values.
5
+
6
+ It can easily be enhanced to include other git features such as branches, diffs, etc
7
+
8
+ Example:
9
+
10
+ ```ruby
11
+
12
+ @gaga = Gaga.new(:path => File.expand_path('..', __FILE__))
13
+ @gaga.clear
14
+
15
+ # SET
16
+
17
+ @gaga['lady'] = "gaga"
18
+
19
+ # GET
20
+
21
+ @gaga['lady'] #=> "gaga"
22
+
23
+ # KEYS
24
+
25
+ @gaga.keys #=> ['lady']
26
+
27
+ # DELETE
28
+
29
+ @gaga.delete('lady') #=> 'gaga'
30
+
31
+ # LOG
32
+
33
+ @gaga.log('key')
34
+
35
+ # Produces:
36
+
37
+ [
38
+ {"message"=>"all clear","committer"=>{"name"=>"Matt Sears", "email"=>"matt@mattsears.com"}, "committed_date"=>"2011-09-05..."},
39
+ {"message"=>"set 'lady' ", "committer"=>{"name"=>"Matt Sears", "email"=>"matt@mattsears.com"}, "committed_date"=>"2011-09-05..."}
40
+ {"message"=>"delete 'lady' ", "committer"=>{"name"=>"Matt Sears", "email"=>"matt@mattsears.com"}, "committed_date"=>"2011-09-05..."}
41
+ ]
42
+
43
+ ```
@@ -0,0 +1,13 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rake/testtask'
5
+ task :default => :test
6
+
7
+ desc 'Run tests (default)'
8
+ Rake::TestTask.new(:test) do |t|
9
+ t.test_files = FileList['test/**/*_test.rb']
10
+ t.ruby_opts = ['-Itest', '-W0']
11
+ t.libs << "lib" << "test"
12
+ t.ruby_opts << '-rubygems' if defined? Gem
13
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "gaga/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "gaga"
7
+ s.version = Gaga::VERSION
8
+ s.authors = ["Matt Sears"]
9
+ s.email = ["matt@mattsears.com"]
10
+ s.homepage = "http://github.com/mattsears/gaga"
11
+ s.summary = %q{Git as a key value store}
12
+ s.description = %q{Git as a key value store}
13
+ s.rubyforge_project = "gaga"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ # specify any dependencies here; for example:
21
+ # s.add_development_dependency "rspec"
22
+ s.add_runtime_dependency "grit"
23
+ end
@@ -0,0 +1,168 @@
1
+ require 'yaml'
2
+ require 'grit'
3
+ require 'gaga/version'
4
+
5
+ class Gaga
6
+
7
+ def initialize(options = {})
8
+ @options = options
9
+ unless ::File.exists?(File.join(path,'.git'))
10
+ Grit::Repo.init(path)
11
+ end
12
+ end
13
+
14
+ # Add the value to the to the store
15
+ #
16
+ # Example
17
+ # @store.set('key', 'value')
18
+ #
19
+ # Returns nothing
20
+ def set(key, value)
21
+ save("set '#{key}'") do |index|
22
+ index.add(key_for(key), encode(value))
23
+ end
24
+ end
25
+
26
+ # Shortcut for #set
27
+ #
28
+ # Example:
29
+ # @store[key] = 'value'
30
+ #
31
+ def []=(key, value)
32
+ set(key, value)
33
+ end
34
+
35
+ # Retrieve the value for the given key with a default value
36
+ #
37
+ # Example:
38
+ # @store.get(key) #=> value
39
+ #
40
+ # Returns the object found in the repo matching the key
41
+ def get(key, value = nil, *)
42
+ if head && blob = head.commit.tree / key_for(key)
43
+ decode(blob.data)
44
+ end
45
+ end
46
+
47
+ # Shortcut for #get
48
+ #
49
+ # Example:
50
+ # @store['key'] #=> value
51
+ #
52
+ def [](key)
53
+ get(key)
54
+ end
55
+
56
+ # Returns an array of key names contained in store
57
+ #
58
+ # Example:
59
+ # @store.keys #=> ['key1', 'key2']
60
+ #
61
+ def keys
62
+ head.commit.tree.contents.map{|blob| deserialize(blob.name) }
63
+ end
64
+
65
+ # Deletes commits matching the given key
66
+ #
67
+ # Example:
68
+ # @store.delete('key')
69
+ #
70
+ # Returns nothing
71
+ def delete(key, *)
72
+ self[key].tap do
73
+ save("deleted #{key}") {|index| index.delete(key_for(key)) }
74
+ end
75
+ end
76
+
77
+ # Deletes all contents of the store
78
+ #
79
+ # Returns nothing
80
+ def clear
81
+ save("all clear") do |index|
82
+ if tree = index.current_tree
83
+ tree.contents.each do |entry|
84
+ index.delete(key_for(entry.name))
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ # The commit log for the given key
91
+ #
92
+ # Example:
93
+ # @store.log('key') #=> [{"message"=>"Updated key"...}]
94
+ #
95
+ # Returns Array of commit data
96
+ def log(key)
97
+ git.log(branch, key_for(key)).map{ |commit| commit.to_hash }
98
+ end
99
+
100
+ # Find the key if exists in the git repo
101
+ #
102
+ # Example:
103
+ # @store.key? 'key' #=> true
104
+ #
105
+ # Returns true if found; false if not found
106
+ def key?(key)
107
+ !(head && head.commit.tree / key_for(key)).nil?
108
+ end
109
+
110
+ private
111
+
112
+ # Format the given key so that it ensures it's git worthy
113
+ def key_for(key)
114
+ key.is_a?(String) ? key : serialize(key)
115
+ end
116
+
117
+ # Given the file path, return a new Grit::Repo if found
118
+ def git
119
+ @git ||= Grit::Repo.new(path)
120
+ end
121
+
122
+ # The git branch to use for this store
123
+ def branch
124
+ @options[:branch] || 'master'
125
+ end
126
+
127
+ # Checks out the branch on the repo
128
+ def head
129
+ git.get_head(branch)
130
+ end
131
+
132
+ # Commits the the value into the git repository with the given commit message
133
+ def save(message)
134
+ index = git.index
135
+ if head
136
+ commit = head.commit
137
+ index.current_tree = commit.tree
138
+ end
139
+ yield index
140
+ index.commit(message, :parents => Array(commit), :head => branch) if index.tree.any?
141
+ end
142
+
143
+ # Converts the value to yaml format
144
+ def encode(value)
145
+ value.to_yaml
146
+ end
147
+
148
+ # Loads value as a Yaml structure
149
+ def decode(value)
150
+ YAML.load(value)
151
+ end
152
+
153
+ # Convert value to byte stream. This allows keys to be objects too
154
+ def serialize(value)
155
+ Marshal.dump(value)
156
+ end
157
+
158
+ # Converts value back to an object.
159
+ def deserialize(value)
160
+ Marshal.restore(value) rescue value
161
+ end
162
+
163
+ # Given that repo path set in the options, return the expanded file path
164
+ def path(key = '')
165
+ @path ||= File.join(File.expand_path(@options[:repo]), key)
166
+ end
167
+
168
+ end
@@ -0,0 +1,3 @@
1
+ class Gaga
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,93 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+ require 'helper'
3
+
4
+ describe Gaga do
5
+
6
+ @types = {
7
+ "String" => ["lady", "gaga"],
8
+ "Object" => [{:lady => :gaga}, {:gaga => :ohai}]
9
+ }
10
+
11
+ before do
12
+ @store = Gaga.new(:repo => tmp_dir)
13
+ @store.clear
14
+ end
15
+
16
+ @types.each do |type, (key, key2)|
17
+
18
+ it "writes String values to keys" do
19
+ @store[key] = "value"
20
+ @store[key].must_equal "value"
21
+ end
22
+
23
+ it "reads from keys" do
24
+ @store[key].must_be_nil
25
+ end
26
+
27
+ it "returns a list of keys" do
28
+ @store[key] = "value"
29
+ @store.keys.must_include(key)
30
+ end
31
+
32
+ it "guarantees that a different String value is retrieved" do
33
+ value = "value"
34
+ @store[key] = value
35
+ @store[key].wont_be_same_as(value)
36
+ end
37
+
38
+ it "writes Object values to keys" do
39
+ @store[key] = {:foo => :bar}
40
+ @store[key].must_equal({:foo => :bar})
41
+ end
42
+
43
+ it "guarantees that a different Object value is retrieved" do
44
+ value = {:foo => :bar}
45
+ @store[key] = value
46
+ @store[key].wont_be_same_as(:foo => :bar)
47
+ end
48
+
49
+ it "returns false from key? if a key is not available" do
50
+ @store.key?(key).must_equal false
51
+ end
52
+
53
+ it "returns true from key? if a key is available" do
54
+ @store[key] = "value"
55
+ @store.key?(key).must_equal true
56
+ end
57
+
58
+ it "removes and return an element with a key from the store via delete if it exists" do
59
+ @store[key] = "value"
60
+ @store.delete(key).must_equal "value"
61
+ @store.key?(key).must_equal false
62
+ end
63
+
64
+ it "returns nil from delete if an element for a key does not exist" do
65
+ @store.delete(key).must_be_nil
66
+ end
67
+
68
+ it "removes all keys from the store with clear" do
69
+ @store[key] = "value"
70
+ @store[key2] = "value2"
71
+ @store.clear
72
+ @store.key?(key).wont_equal true
73
+ @store.key?(key2).wont_equal true
74
+ end
75
+
76
+ it "does not run the block if the #{type} key is available" do
77
+ @store[key] = "value"
78
+ unaltered = "unaltered"
79
+ @store.get(key) { unaltered = "altered" }
80
+ unaltered.must_equal "unaltered"
81
+ end
82
+
83
+ it "stores #{key} values with #set" do
84
+ @store.set(key, "value")
85
+ @store[key].must_equal "value"
86
+ end
87
+
88
+ it "returns a list of commit history for the key" do
89
+ @store.log(key).wont_be_empty
90
+ end
91
+ end
92
+
93
+ end
@@ -0,0 +1,21 @@
1
+ require "bundler"
2
+ Bundler.setup
3
+
4
+ require 'minitest/autorun'
5
+ require 'minitest/pride'
6
+
7
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
8
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
9
+
10
+ require 'gaga'
11
+
12
+ TMP_DIR = '/tmp/gaga_test'
13
+
14
+ def tmp_dir
15
+ TMP_DIR
16
+ end
17
+
18
+ def remove_tmpdir!(passed_dir = nil)
19
+ FileUtils.rm_rf(passed_dir || tmp_dir)
20
+ end
21
+
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gaga
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Matt Sears
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-10-23 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: grit
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ type: :runtime
25
+ version_requirements: *id001
26
+ description: Git as a key value store
27
+ email:
28
+ - matt@mattsears.com
29
+ executables: []
30
+
31
+ extensions: []
32
+
33
+ extra_rdoc_files: []
34
+
35
+ files:
36
+ - .gitignore
37
+ - Gemfile
38
+ - README.md
39
+ - Rakefile
40
+ - gaga.gemspec
41
+ - lib/gaga.rb
42
+ - lib/gaga/version.rb
43
+ - test/gaga_test.rb
44
+ - test/helper.rb
45
+ homepage: http://github.com/mattsears/gaga
46
+ licenses: []
47
+
48
+ post_install_message:
49
+ rdoc_options: []
50
+
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ requirements: []
66
+
67
+ rubyforge_project: gaga
68
+ rubygems_version: 1.8.10
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: Git as a key value store
72
+ test_files:
73
+ - test/gaga_test.rb
74
+ - test/helper.rb