rufus-cloche 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/CHANGELOG.txt +6 -0
  2. data/CREDITS.txt +4 -0
  3. data/README.rdoc +91 -0
  4. data/test/test.rb +152 -0
  5. metadata +62 -0
data/CHANGELOG.txt ADDED
@@ -0,0 +1,6 @@
1
+
2
+ = rufus-cloche CHANGELOG.txt
3
+
4
+
5
+ == rufus-cloche - 0.1.0 released 2009/11/16
6
+
data/CREDITS.txt ADDED
@@ -0,0 +1,4 @@
1
+
2
+ many thanks to Brian Lopez for yajl-ruby
3
+ http://github.com/brianmario
4
+
data/README.rdoc ADDED
@@ -0,0 +1,91 @@
1
+
2
+ = rufus-cloche
3
+
4
+ A very stupid local JSON store.
5
+
6
+ It's built on top of yajl-ruby and File.lock. Defaults to 'json' (or 'json_pure') if yajl-ruby is not present (it's probably just a "gem install yajl-ruby" away.
7
+
8
+ Strives to be process-safe and thread-safe.
9
+
10
+ The philosophy here is : every document has a revision number. You have to provide the latest revision number in order to update sucessfully a document (else the 'put' will fail and you'll return the latest version of the document (as a new starting point)).
11
+
12
+ A cloche assumes your documents have a 'type' and it stores documents in separate dirs, one per type.
13
+
14
+
15
+ == usage
16
+
17
+ Basic operations :
18
+
19
+ require 'rubygems'
20
+ require 'rufus-cloche' # gem install rufus-cloche
21
+
22
+ c = Rufus::Cloche.new(:dir => 'my_cloche')
23
+
24
+ doc = { '_id' => 'invitation05', 'type' => 'letter', 'to' => 'The Duke' }
25
+ # documents are Hash instances, with an '_id' and a 'type' key.
26
+
27
+ d = c.put(doc)
28
+
29
+ p d
30
+ # => nil
31
+ # #put returned nil, the 'insertion' was successful
32
+
33
+ p doc['_rev']
34
+ # => 0
35
+ # Cloche added the '_rev' key and set its value to 0.
36
+
37
+ # ... meanwhile, someone in another process upated the document
38
+ # we're trying to put an updated version ...
39
+
40
+ doc['body'] = "Dear Monty, it's been a while since El Alamein..."
41
+
42
+ d = c.put(doc)
43
+
44
+ p d
45
+ # => { "_id" => "invitation05", "type"=>"letter", "to" => "The Count", "_rev" => 1 }
46
+ #
47
+ # the update failed, the method returned the current version of the document
48
+
49
+ It's OK to get a document, but it's sometimes better to get many of them :
50
+
51
+ docs = get_many('letter')
52
+ # returns an array containing *all* the documents with the type 'letter'
53
+
54
+ docs = get_many('letter', /^invitation/)
55
+ # returns all the documents whose _id begins with "invitation"
56
+
57
+ docs = get_many('letter', /\/2009\//)
58
+ # returns all the 2009 letters (assuming their _id contains the string "/2009/"
59
+
60
+
61
+ == mailing list
62
+
63
+ On the rufus-ruby list :
64
+
65
+ http://groups.google.com/group/rufus-ruby
66
+
67
+
68
+ == issue tracker
69
+
70
+ http://github.com/jmettraux/rufus-cloche/issues
71
+
72
+
73
+ == irc
74
+
75
+ irc.freenode.net #ruote
76
+
77
+
78
+ == the rest of Rufus
79
+
80
+ http://rufus.rubyforge.org
81
+
82
+
83
+ == authors
84
+
85
+ * John Mettraux, jmettraux@gmail.com, http://jmettraux.wordpress.com
86
+
87
+
88
+ == license
89
+
90
+ MIT
91
+
data/test/test.rb ADDED
@@ -0,0 +1,152 @@
1
+
2
+ #
3
+ # testing cloche
4
+ #
5
+ # Fri Nov 13 09:09:58 JST 2009
6
+ #
7
+
8
+ ROOT = File.join(File.dirname(__FILE__), '..')
9
+
10
+ require 'test/unit'
11
+ require File.join(ROOT, %w[ lib rufus cloche.rb ])
12
+
13
+ class ClocheTest < Test::Unit::TestCase
14
+
15
+ def setup
16
+ @c_dir = File.join(ROOT, 'tcloche')
17
+ FileUtils.rm_rf(@c_dir) rescue nil
18
+ @c = Rufus::Cloche.new(:dir => @c_dir)
19
+ end
20
+ #def teardown
21
+ #end
22
+
23
+ def test_put
24
+
25
+ r = @c.put({ '_id' => 'john', 'type' => 'person', 'eyes' => 'green' })
26
+
27
+ assert_nil r
28
+
29
+ h = fetch('person', 'john')
30
+ assert_equal 0, h['_rev']
31
+ end
32
+
33
+ def test_depth
34
+
35
+ @c.put({ '_id' => 'john', 'type' => 'person', 'eyes' => 'green' })
36
+
37
+ assert_equal(
38
+ "test/../tcloche/person/hn/john.json",
39
+ Dir[File.join(@c_dir, %w[ ** *.json ])].first)
40
+ end
41
+
42
+ def test_small_id
43
+
44
+ r = @c.put({ '_id' => '0', 'type' => 'person', 'eyes' => 'green' })
45
+
46
+ assert_nil r
47
+ end
48
+
49
+ def test_put_insufficient_doc
50
+
51
+ assert_raise ArgumentError do
52
+ @c.put({ '_id' => 'john', 'eyes' => 'shut' })
53
+ end
54
+ end
55
+
56
+ def test_put_fail
57
+
58
+ @c.put({ '_id' => 'john', 'type' => 'person', 'eyes' => 'green' })
59
+ r = @c.put({ '_id' => 'john', 'type' => 'person', 'eyes' => 'brown' })
60
+
61
+ assert_equal 0, r['_rev']
62
+
63
+ h = fetch('person', 'john')
64
+ assert_equal 'green', h['eyes']
65
+ end
66
+
67
+ def test_re_put
68
+
69
+ @c.put(
70
+ { '_id' => 'john', 'type' => 'person', 'eyes' => 'green' })
71
+
72
+ r = @c.put(
73
+ { '_id' => 'john', 'type' => 'person', 'eyes' => 'blue', '_rev' => 0 })
74
+
75
+ assert_nil r
76
+
77
+ h = fetch('person', 'john')
78
+ assert_equal 1, h['_rev']
79
+ end
80
+
81
+ def test_delete_missing
82
+
83
+ r = @c.delete({ '_id' => 'john', 'type' => 'person', 'eyes' => 'green' })
84
+
85
+ assert_not_nil r
86
+ end
87
+
88
+ def test_delete
89
+
90
+ @c.put({ '_id' => 'john', 'type' => 'person', 'eyes' => 'green' })
91
+
92
+ r = @c.delete({ '_id' => 'john', 'type' => 'person', '_rev' => 0 })
93
+
94
+ assert_nil r
95
+ assert_equal false, File.exist?(File.join(ROOT, 'person', 'john'))
96
+ end
97
+
98
+ def test_delete_fail
99
+
100
+ @c.put({ '_id' => 'john', 'type' => 'person', 'eyes' => 'green' })
101
+
102
+ r = @c.delete({ '_id' => 'john', 'type' => 'person', 'eyes' => 'green' })
103
+
104
+ assert_not_nil r
105
+ end
106
+
107
+ def test_get_many
108
+
109
+ @c.put({ '_id' => 'john', 'type' => 'person', 'eyes' => 'green' })
110
+ @c.put({ '_id' => 'jami', 'type' => 'person', 'eyes' => 'blue' })
111
+ @c.put({ '_id' => 'minehiko', 'type' => 'person', 'eyes' => 'brown' })
112
+ @c.put({ '_id' => 'hiro', 'type' => 'person', 'eyes' => 'brown' })
113
+ @c.put({ '_id' => 'chicko-chan', 'type' => 'animal', 'eyes' => 'black' })
114
+
115
+ assert_equal(
116
+ %w[ blue brown brown green ],
117
+ @c.get_many('person').collect { |e| e['eyes'] }.sort)
118
+ end
119
+
120
+ def test_get_many_with_key_match
121
+
122
+ @c.put({ '_id' => 'john', 'type' => 'person', 'eyes' => 'green' })
123
+ @c.put({ '_id' => 'jami', 'type' => 'person', 'eyes' => 'blue' })
124
+ @c.put({ '_id' => 'minehiko', 'type' => 'person', 'eyes' => 'brown' })
125
+ @c.put({ '_id' => 'hiro', 'type' => 'person', 'eyes' => 'brown' })
126
+ @c.put({ '_id' => 'chicko-chan', 'type' => 'animal', 'eyes' => 'black' })
127
+
128
+ assert_equal 2, @c.get_many('person', /^j/).size
129
+ end
130
+
131
+ def test_get_many_key_order
132
+
133
+ @c.put({ '_id' => 'john', 'type' => 'person', 'eyes' => 'green' })
134
+ @c.put({ '_id' => 'jami', 'type' => 'person', 'eyes' => 'blue' })
135
+ @c.put({ '_id' => 'minehiko', 'type' => 'person', 'eyes' => 'brown' })
136
+ @c.put({ '_id' => 'hiro', 'type' => 'person', 'eyes' => 'brown' })
137
+ @c.put({ '_id' => 'chicko-chan', 'type' => 'animal', 'eyes' => 'black' })
138
+
139
+ assert_equal(
140
+ %w[ hiro jami john minehiko ],
141
+ @c.get_many('person').collect { |e| e['_id'] })
142
+ end
143
+
144
+ protected
145
+
146
+ def fetch (type, key)
147
+
148
+ s = File.read(File.join(ROOT, 'tcloche', type, key[-2, 2], "#{key}.json"))
149
+ Rufus::Cloche.json_decode(s)
150
+ end
151
+ end
152
+
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rufus-cloche
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - John Mettraux
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-16 00:00:00 +09:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: "\n\
17
+ A very stupid JSON hash store.\n\n\
18
+ It's built on top of yajl-ruby and File.lock. Defaults to 'json' (or 'json_pure') if yajl-ruby is not present (it's probably just a \"gem install yajl-ruby\" away.\n\n\
19
+ Strives to be process-safe and thread-safe.\n "
20
+ email: jmettraux@gmail.com
21
+ executables: []
22
+
23
+ extensions: []
24
+
25
+ extra_rdoc_files:
26
+ - README.rdoc
27
+ - CHANGELOG.txt
28
+ - CREDITS.txt
29
+ files:
30
+ - README.rdoc
31
+ - CHANGELOG.txt
32
+ - CREDITS.txt
33
+ has_rdoc: true
34
+ homepage: http://github.com/jmettraux/rufus-cloche/
35
+ licenses: []
36
+
37
+ post_install_message:
38
+ rdoc_options: []
39
+
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ version:
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ version:
54
+ requirements: []
55
+
56
+ rubyforge_project: rufus
57
+ rubygems_version: 1.3.5
58
+ signing_key:
59
+ specification_version: 3
60
+ summary: a very stupid JSON hash store
61
+ test_files:
62
+ - test/test.rb