rufus-cloche 0.1.0

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.
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