georgi-git_store 0.1 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +81 -15
- data/git_store.gemspec +1 -1
- data/lib/git_store.rb +19 -9
- metadata +1 -1
data/README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
Git Store - using Git as versioned data store in Ruby
|
2
|
+
=====================================================
|
3
3
|
|
4
4
|
GitStore is a small Ruby library, providing an easy interface to the
|
5
5
|
version control system [Git][1]. It aims to use Git as a versioned
|
@@ -7,16 +7,31 @@ data store much like the well known PStore. Basically GitStore checks
|
|
7
7
|
out the repository into a in-memory representation, which can be
|
8
8
|
modified and finally committed. In this way your data is stored in a
|
9
9
|
folder structure and can be checked out and examined, but the
|
10
|
-
application may access the data in a convenient hash-like way.
|
10
|
+
application may access the data in a convenient hash-like way. This
|
11
|
+
library is based on [Grit][2], the main technology behind [GitHub][3].
|
12
|
+
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
GitStore can be installed as gem easily, if you have RubyGems 1.2.0:
|
17
|
+
|
18
|
+
$ gem sources -a http://gems.github.com you only have to do this once)
|
19
|
+
$ sudo gem install georgi-git_store
|
20
|
+
|
21
|
+
If you don't have RubyGems 1.2.0, you may download the package on the
|
22
|
+
[github page][4] and build the gem yourself:
|
23
|
+
|
24
|
+
$ gem build git_store.gemspec
|
25
|
+
$ sudo gem install git_store
|
11
26
|
|
12
|
-
This library is based on [Grit][2], the main technology behind
|
13
|
-
[GitHub][3].
|
14
27
|
|
15
28
|
## Usage Example
|
16
29
|
|
17
30
|
First thing you should do, is to initialize a new git repository.
|
18
31
|
|
19
|
-
|
32
|
+
$ mkdir test
|
33
|
+
$ cd test
|
34
|
+
$ git init
|
20
35
|
|
21
36
|
Now you can instantiate a GitStore instance and store some data. The
|
22
37
|
data will be serialized depending on the file extension. So for YAML
|
@@ -32,19 +47,34 @@ storage you can use the 'yml' extension:
|
|
32
47
|
|
33
48
|
store.commit 'Added user and page'
|
34
49
|
|
35
|
-
Note that
|
36
|
-
|
50
|
+
Note that directories will be created automatically.
|
51
|
+
|
52
|
+
Another way to access a path is:
|
37
53
|
|
38
54
|
store[config', 'wiki.yml'] = { 'name' => 'My Personal Wiki' }
|
39
55
|
|
40
|
-
|
41
|
-
|
56
|
+
Finally you can access the git store as a Hash of Hashes, but in this
|
57
|
+
case you have to create the Tree objects manually:
|
58
|
+
|
59
|
+
store['users'] = GitStore::Tree.new
|
60
|
+
store['users']['matthias.yml'] = User.new('Matthias')
|
61
|
+
|
62
|
+
## Where is my data?
|
63
|
+
|
64
|
+
When you call the `commit` method, your data is written back straight
|
65
|
+
into the git repository. No intermediate file representation. So if
|
66
|
+
you want to look into your data, you can use some git browser like
|
67
|
+
[git-gui][6] or just checkout the files:
|
68
|
+
|
69
|
+
$ git checkout
|
70
|
+
|
42
71
|
|
43
72
|
## Iteration
|
44
73
|
|
45
|
-
Iterating over the
|
46
|
-
|
47
|
-
|
74
|
+
Iterating over the data objects is quite easy. Furthermore you can
|
75
|
+
iterate over trees and subtrees, so you can partition your data in a
|
76
|
+
meaningful way. For example you may separate the config files and the
|
77
|
+
pages of a wiki:
|
48
78
|
|
49
79
|
store['pages/home.yml'] = WikiPage.new('matthias', 'Home', 'This is the home page...')
|
50
80
|
store['pages/about.yml'] = WikiPage.new('matthias', About', 'About this site...')
|
@@ -54,13 +84,49 @@ a clever directory structure:
|
|
54
84
|
store.each { |obj| ... } # yields all pages and the config hash
|
55
85
|
store['pages'].each { |page| ... } # yields only the pages
|
56
86
|
|
57
|
-
|
87
|
+
|
88
|
+
## Serialization
|
89
|
+
|
90
|
+
Serialization is dependent on the filename extension. You can add more
|
91
|
+
handlers if you like, the interface is like this:
|
92
|
+
|
93
|
+
class YAMLHandler
|
94
|
+
def read(id, name, data)
|
95
|
+
YAML.load(data)
|
96
|
+
end
|
97
|
+
|
98
|
+
def write(data)
|
99
|
+
data.to_yaml
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
GitStore::Handler['yml'] = YAMLHandler.new
|
104
|
+
|
105
|
+
|
106
|
+
Shinmun uses its own handler for files with `md` extension:
|
107
|
+
|
108
|
+
class PostHandler
|
109
|
+
def read(name, data)
|
110
|
+
Post.new(:filename => name, :src => data)
|
111
|
+
end
|
112
|
+
|
113
|
+
def write(post)
|
114
|
+
post.dump
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
GitStore::Handler[md'] = PostHandler.new
|
119
|
+
|
120
|
+
|
121
|
+
## Related Work
|
58
122
|
|
59
123
|
John Wiegley already has done [something similar for Python][4]. His
|
60
124
|
implementation has its own git interface, GitStore uses the wonderful
|
61
125
|
[Grit][2] library.
|
62
126
|
|
63
127
|
[1]: http://git.or.cz/
|
64
|
-
[2]: http://github.com/mojombo/grit
|
128
|
+
[2]: http://github.com/mojombo/grit
|
65
129
|
[3]: http://github.com/
|
66
130
|
[4]: http://www.newartisans.com/blog_files/git.versioned.data.store.php
|
131
|
+
[5]: http://github.com/georgi/git_store
|
132
|
+
[6]: http://www.kernel.org/pub/software/scm/git/docs/git-gui.html
|
data/git_store.gemspec
CHANGED
data/lib/git_store.rb
CHANGED
@@ -1,10 +1,22 @@
|
|
1
1
|
require 'grit'
|
2
|
-
|
2
|
+
|
3
|
+
# This fix ensures sorted yaml maps.
|
4
|
+
class Hash
|
5
|
+
def to_yaml( opts = {} )
|
6
|
+
YAML::quick_emit( object_id, opts ) do |out|
|
7
|
+
out.map( taguri, to_yaml_style ) do |map|
|
8
|
+
sort_by { |k, v| k.to_s }.each do |k, v|
|
9
|
+
map.add( k, v )
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
3
15
|
|
4
16
|
class GitStore
|
5
17
|
|
6
18
|
class DefaultHandler
|
7
|
-
def read(
|
19
|
+
def read(name, data)
|
8
20
|
data
|
9
21
|
end
|
10
22
|
|
@@ -14,7 +26,7 @@ class GitStore
|
|
14
26
|
end
|
15
27
|
|
16
28
|
class YAMLHandler
|
17
|
-
def read(
|
29
|
+
def read(name, data)
|
18
30
|
YAML.load(data)
|
19
31
|
end
|
20
32
|
|
@@ -24,13 +36,13 @@ class GitStore
|
|
24
36
|
end
|
25
37
|
|
26
38
|
class RubyHandler
|
27
|
-
def read(
|
39
|
+
def read(name, data)
|
28
40
|
Object.module_eval(data)
|
29
41
|
end
|
30
42
|
end
|
31
43
|
|
32
44
|
class ERBHandler
|
33
|
-
def read(
|
45
|
+
def read(name, data)
|
34
46
|
ERB.new(data)
|
35
47
|
end
|
36
48
|
end
|
@@ -52,7 +64,6 @@ class GitStore
|
|
52
64
|
def initialize(*args)
|
53
65
|
if args.first.is_a?(Grit::Blob)
|
54
66
|
@blob = args.first
|
55
|
-
@id = @blob.id
|
56
67
|
@name = @blob.name
|
57
68
|
else
|
58
69
|
@name = args[0]
|
@@ -65,7 +76,7 @@ class GitStore
|
|
65
76
|
end
|
66
77
|
|
67
78
|
def load(data)
|
68
|
-
@data = handler.read(
|
79
|
+
@data = handler.read(name, data)
|
69
80
|
end
|
70
81
|
|
71
82
|
def handler
|
@@ -93,7 +104,7 @@ class GitStore
|
|
93
104
|
class Tree
|
94
105
|
include Enumerable
|
95
106
|
|
96
|
-
attr_reader :
|
107
|
+
attr_reader :data
|
97
108
|
attr_accessor :name
|
98
109
|
|
99
110
|
def initialize(name = nil)
|
@@ -102,7 +113,6 @@ class GitStore
|
|
102
113
|
end
|
103
114
|
|
104
115
|
def load(tree)
|
105
|
-
@id = tree.id
|
106
116
|
@name = tree.name
|
107
117
|
@data = tree.contents.inject({}) do |hash, file|
|
108
118
|
if file.is_a?(Grit::Tree)
|