ccp 0.2.9 → 0.3.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.
data/ccp.gemspec CHANGED
@@ -5,6 +5,7 @@ require "ccp/version"
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "ccp"
7
7
  s.version = Ccp::VERSION
8
+ s.license = 'MIT'
8
9
  s.authors = ["maiha"]
9
10
  s.email = ["maiha@wota.jp"]
10
11
  s.homepage = "http://github.com/maiha/ccp"
data/lib/ccp.rb CHANGED
@@ -14,5 +14,6 @@ module Ccp
14
14
  autoload :Receivers, 'ccp/receivers'
15
15
  autoload :Persistent, 'ccp/persistent'
16
16
  autoload :Serializers, 'ccp/serializers'
17
+ autoload :Storage, 'ccp/storage'
17
18
  autoload :Kvs, 'ccp/kvs'
18
19
  end
data/lib/ccp/kvs/core.rb CHANGED
@@ -4,6 +4,8 @@ module Ccp
4
4
  def get(k) ; raise NotImplementedError, "subclass resposibility"; end
5
5
  def set(k,v) ; raise NotImplementedError, "subclass resposibility"; end
6
6
  def del(k) ; raise NotImplementedError, "subclass resposibility"; end
7
+ def keys ; raise NotImplementedError, "subclass resposibility"; end
8
+ def read! ; keys.inject({}){|h,k| h[k] = get(k); h } ; end
7
9
 
8
10
  def open(*) ; end
9
11
  def close ; end
@@ -16,6 +18,10 @@ module Ccp
16
18
  def put(k,v) ; set(k,v) ; end
17
19
  def out(k) ; del(k) ; end
18
20
 
21
+ def codec!(c); @codec = Ccp::Serializers[c] ; self ; end
22
+ def encode(v); @codec ? @codec.encode(v) : v ; end
23
+ def decode(v); (v && @codec) ? @codec.decode(v) : v ; end
24
+
19
25
  def ext; self.class.name.split(/::/).last.to_s.downcase; end
20
26
  def self.included(klass)
21
27
  klass.class_eval do
data/lib/ccp/kvs/hash.rb CHANGED
@@ -3,14 +3,16 @@ module Ccp
3
3
  class Hash
4
4
  include Core
5
5
 
6
+ delegate :keys, :to=>"@db"
7
+
6
8
  def initialize
7
9
  @db = {}
8
10
  end
9
11
 
10
- def get(k) ; @db[k.to_s] ; end
11
- def set(k,v) ; @db[k.to_s] = v.to_s ; end
12
- def del(k) ; @db.delete(k.to_s) ; end
13
- def count ; @db.size ; end
12
+ def get(k) ; decode(@db[k.to_s]) ; end
13
+ def set(k,v) ; @db[k.to_s] = encode(v).to_s; end
14
+ def del(k) ; decode(@db.delete(k.to_s)) ; end
15
+ def count ; @db.size ; end
14
16
  end
15
17
  end
16
18
  end
data/lib/ccp/kvs/tch.rb CHANGED
@@ -7,6 +7,8 @@ module Ccp
7
7
  def set(k,v) ; W{ super }; end
8
8
  def del(k) ; W{ super }; end
9
9
  def count ; R{ super }; end
10
+ def keys ; R{ super }; end
11
+ def read! ; R{ super }; end
10
12
  end
11
13
  end
12
14
  end
@@ -19,10 +19,6 @@ module Ccp
19
19
  ######################################################################
20
20
  ### kvs
21
21
 
22
- def get(k) ; @db[k] ; end
23
- def set(k,v) ; @db[k] = v ; end
24
- def del(k) ; @db.delete(k) ; end
25
-
26
22
  def path
27
23
  file = @source.to_s.sub(/#.*$/, '') # parse "foo.tch#mode=r"
28
24
  Pathname(file)
@@ -30,7 +26,11 @@ module Ccp
30
26
 
31
27
  private
32
28
  def tokyo_error!(label = nil)
33
- raise Ccp::Kvs::Tokyo::Error, "%s%s" % [label, error_message]
29
+ raise Ccp::Kvs::Tokyo::Error, "%s%s (%s)" % [label, error_message, @source]
30
+ end
31
+
32
+ def tokyo_error?
33
+ @db.ecode != HDB::ESUCCESS
34
34
  end
35
35
 
36
36
  def error_message
@@ -16,7 +16,7 @@ module Ccp
16
16
  tryR("get")
17
17
  v = @db[k.to_s]
18
18
  if v
19
- return v
19
+ return decode(v)
20
20
  else
21
21
  if @db.ecode == HDB::ENOREC
22
22
  return nil
@@ -28,15 +28,17 @@ module Ccp
28
28
 
29
29
  def set(k,v)
30
30
  tryW("set")
31
- @db[k.to_s] = v.to_s or tokyo_error!("set(%s): " % k)
31
+ val = encode(v)
32
+ @db[k.to_s] = val or
33
+ tokyo_error!("set(%s): " % k)
32
34
  end
33
35
 
34
36
  def del(k)
35
37
  tryW("del")
36
- v = get(k)
38
+ v = @db[k.to_s]
37
39
  if v
38
- if @db.delete(k.to_s)
39
- return v
40
+ if @db.delete(k.to_s)
41
+ return decode(v)
40
42
  else
41
43
  tokyo_error!("del(%s): " % k)
42
44
  end
@@ -50,6 +52,37 @@ module Ccp
50
52
  return @db.rnum
51
53
  end
52
54
 
55
+ ######################################################################
56
+ ### iterator
57
+
58
+ def each(&block)
59
+ each_keys do |key|
60
+ block.call(get(key))
61
+ end
62
+ end
63
+
64
+ def each_pair(&block)
65
+ each_keys do |key|
66
+ block.call(key, get(key))
67
+ end
68
+ end
69
+
70
+ def each_keys(&block)
71
+ tryR("each_keys")
72
+ @db.iterinit
73
+ while key = @db.iternext
74
+ block.call(key)
75
+ end
76
+ end
77
+
78
+ def keys
79
+ array = []
80
+ each_keys do |key|
81
+ array << key
82
+ end
83
+ return array
84
+ end
85
+
53
86
  end
54
87
  end
55
88
  end
@@ -0,0 +1,62 @@
1
+ module Ccp
2
+ class Storage
3
+ NotFound = Class.new(RuntimeError)
4
+
5
+ def self.load(path)
6
+ array = path.split(".")
7
+ kvs = Ccp::Kvs[array.pop]
8
+ codec = Ccp::Serializers[array.pop]
9
+ return new(path, kvs, codec)
10
+ end
11
+
12
+ attr_reader :source, :kvs, :codec, :path
13
+ delegate :get, :set, :del, :keys, :read!, :to=>"@kvs"
14
+
15
+ def initialize(source, kvs, codec)
16
+ @source = source
17
+ @codec = codec
18
+ @path = Pathname(source)
19
+ @kvs = kvs.new(source).codec!(codec)
20
+ @tables = {}
21
+ end
22
+
23
+ ######################################################################
24
+ ### meta kvs
25
+
26
+ def table_names
27
+ tables # force to update @tables
28
+ @tables.keys
29
+ end
30
+
31
+ def tables
32
+ files = Dir.chdir(@path) { Dir["**/*.#{@kvs.ext}"] }
33
+ files.map{|file|
34
+ name = file.sub(/(\.#{@codec.ext})?(\.#{@kvs.ext})?$/, '')
35
+ table(name, file)
36
+ }
37
+ end
38
+
39
+ def table(name, file = nil)
40
+ @tables[name.to_s] ||= (
41
+ file ||= "%s.%s.%s" % [name, @codec.ext, @kvs.ext]
42
+ Storage.new((@path + file).to_s, @kvs.class, @codec)
43
+ )
44
+ end
45
+
46
+ ######################################################################
47
+ ### kvs
48
+
49
+ def read!
50
+ if @path.directory?
51
+ tables
52
+ hash = {}
53
+ @tables.each_pair do |k, kvs|
54
+ hash[k] = kvs.read!
55
+ end
56
+ return hash
57
+ else
58
+ return @kvs.read!
59
+ end
60
+ end
61
+ end
62
+ end
data/lib/ccp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ccp
2
- VERSION = "0.2.9"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -8,5 +8,6 @@ describe Ccp::Kvs::Core do
8
8
  it { should respond_to("get") }
9
9
  it { should respond_to("set") }
10
10
  it { should respond_to("del") }
11
+ it { should respond_to("keys") }
11
12
  it { should respond_to("touch") }
12
13
  end
data/spec/kvs/kvs_spec.rb CHANGED
@@ -1,15 +1,14 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  require 'spec_helper'
3
3
 
4
- kvss = []
5
- kvss << Ccp::Kvs::Hash.new
6
- kvss << Ccp::Kvs::Tch.new("#{tmp_path}/kvs/foo.tch")
7
-
8
- kvss.each do |kvs|
9
- describe kvs do
4
+ kvs_args = {}
5
+ kvs_args["tch"] = "#{tmp_path}/kvs/foo.tch"
6
+
7
+ Ccp::Kvs.each do |klass|
8
+ describe klass do
10
9
  before { FileUtils.rm_rf(tmp_path) if tmp_path.directory? }
11
10
 
12
- its(:ext) { should == kvs.class.ext }
11
+ let(:kvs) { kvs_args[klass.ext] ? klass.new(*kvs_args[klass.ext]) : klass.new }
13
12
 
14
13
  describe "#get, #set, #out" do
15
14
  let(:key) { raise "Sub context responsibility" }
@@ -34,11 +33,59 @@ kvss.each do |kvs|
34
33
  it { should be }
35
34
  end
36
35
 
37
- context ":foo => 2" do
36
+ context ":foo => '2'" do
38
37
  let(:key) { :foo }
39
- let(:val) { 2 }
38
+ let(:val) { "2" }
40
39
  it { should be }
41
40
  end
42
41
  end
42
+
43
+ describe "#get, #set, #ou (with msgpack)t" do
44
+ let(:key) { raise "Sub context responsibility" }
45
+ let(:val) { raise "Sub context responsibility" }
46
+
47
+ before { kvs.codec! :msgpack }
48
+
49
+ subject {
50
+ k = kvs
51
+ k.touch
52
+ k.count.should == 0
53
+ k.get(key).should == nil
54
+ k.set(key, val)
55
+ k.get(key).should == val
56
+ k.count.should == 1
57
+ k.out(key).should == val
58
+ k.get(key).should == nil
59
+ k
60
+ }
61
+
62
+ context "nil" do
63
+ let(:key) { :foo }
64
+ let(:val) { nil }
65
+ it { should be }
66
+ end
67
+
68
+ context ":foo => [true, nil]" do
69
+ let(:key) { :foo }
70
+ let(:val) { [true, nil] }
71
+ it { should be }
72
+ end
73
+ end
74
+
75
+ describe "#read!" do
76
+ specify do
77
+ kvs.touch
78
+ kvs.codec! :json
79
+ kvs.set(:a, 1)
80
+ kvs.set(:b, ["x", 0])
81
+ kvs.read!.should == {"a"=>1, "b"=>["x", 0]}
82
+ end
83
+ end
84
+
85
+ describe "#codec!" do
86
+ specify "return self" do
87
+ kvs.codec!(:msgpack).should == kvs
88
+ end
89
+ end
43
90
  end
44
91
  end
@@ -140,11 +140,11 @@ describe Ccp::Kvs::Tokyo::Cabinet do
140
140
 
141
141
  context "(for write)" do
142
142
  before { kvs.W! }
143
- specify { kvs.set("foo", 2).should == "2" }
143
+ specify { lambda { kvs.set("foo", 2) }.should_not raise_error }
144
144
  end
145
145
 
146
146
  context "(for write block)" do
147
- specify { kvs.W{ kvs.set("foo", 2) }.should == "2" }
147
+ specify { lambda { kvs.W{ kvs.set("foo", 2) }.should_not raise_error } }
148
148
  end
149
149
  end
150
150
 
@@ -205,4 +205,17 @@ describe Ccp::Kvs::Tokyo::Cabinet do
205
205
  end
206
206
  end
207
207
 
208
+ ######################################################################
209
+ ### keys
210
+
211
+ describe "#keys" do
212
+ specify do
213
+ put(:foo, 1)
214
+ put(:bar, 2)
215
+ put(:baz, 3)
216
+
217
+ kvs.R!
218
+ kvs.keys.sort.should == %w( bar baz foo )
219
+ end
220
+ end
208
221
  end
@@ -0,0 +1,72 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'spec_helper'
3
+
4
+ describe Ccp::Storage do
5
+ specify ".load" do
6
+ Ccp::Storage.should respond_to(:load)
7
+ end
8
+
9
+ describe ".load" do
10
+ context "('tmp/foo.json.tch')" do
11
+ subject { Ccp::Storage.load('tmp/foo.json.tch') }
12
+ its(:source) { should == 'tmp/foo.json.tch' }
13
+ its(:kvs) { should be_kind_of(Ccp::Kvs::Tch) }
14
+ its(:codec) { should == Ccp::Serializers::Json }
15
+
16
+ describe "table(:foo)" do
17
+ subject { Ccp::Storage.load('tmp/foo.json.tch').table(:bar) }
18
+ its(:source) { should == 'tmp/foo.json.tch/bar.json.tch' }
19
+ its(:kvs) { should be_kind_of(Ccp::Kvs::Tch) }
20
+ its(:codec) { should == Ccp::Serializers::Json }
21
+ end
22
+ end
23
+
24
+ context "('tmp/foo.msgpack.tch')" do
25
+ subject { Ccp::Storage.load('tmp/foo.msgpack.tch') }
26
+ its(:source) { should == 'tmp/foo.msgpack.tch' }
27
+ its(:kvs) { should be_kind_of(Ccp::Kvs::Tch) }
28
+ its(:codec) { should == Ccp::Serializers::Msgpack }
29
+ end
30
+ end
31
+
32
+ describe "#read!" do
33
+ before { FileUtils.rm_rf(tmp_path) if tmp_path.directory? }
34
+
35
+ context "(file)" do
36
+ let(:tch) { tmp_path + "foo.json.tch" }
37
+ subject { Ccp::Storage.new(tch, Ccp::Kvs::Tch, Ccp::Serializers::Json) }
38
+ before {
39
+ tch.parent.mkpath
40
+ system("tchmgr create #{tch}")
41
+ system("tchmgr put #{tch} a '[1,2]'")
42
+ system("tchmgr put #{tch} b 0.1")
43
+ }
44
+ specify do
45
+ subject.read!.should == {"a" => [1, 2], "b" => 0.1}
46
+ end
47
+ end
48
+
49
+ context "(directory)" do
50
+ let(:tch) { tmp_path + "foo.json.tch" }
51
+ subject { Ccp::Storage.new(tch, Ccp::Kvs::Tch, Ccp::Serializers::Json) }
52
+ before {
53
+ tch.mkpath
54
+ system("tchmgr create #{tch}/a.json.tch")
55
+ system("tchmgr put #{tch}/a.json.tch x '[1,2]'")
56
+ system("tchmgr put #{tch}/a.json.tch y []")
57
+ system("tchmgr create #{tch}/b.json.tch")
58
+ system("tchmgr put #{tch}/b.json.tch y 0.1")
59
+ }
60
+ specify do
61
+ subject.read!.should == {
62
+ "a" => {"x" => [1, 2], "y" => []},
63
+ "b" => {"y" => 0.1},
64
+ }
65
+ end
66
+ end
67
+
68
+ end
69
+
70
+ # it { should respond_to(:tables) }
71
+ # it { should respond_to(:table) }
72
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ccp
3
3
  version: !ruby/object:Gem::Version
4
- hash: 5
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 2
9
- - 9
10
- version: 0.2.9
8
+ - 3
9
+ - 0
10
+ version: 0.3.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - maiha
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2013-08-22 00:00:00 Z
18
+ date: 2013-08-23 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: activesupport
@@ -220,6 +220,7 @@ files:
220
220
  - lib/ccp/serializers/json.rb
221
221
  - lib/ccp/serializers/msgpack.rb
222
222
  - lib/ccp/serializers/yaml.rb
223
+ - lib/ccp/storage.rb
223
224
  - lib/ccp/utils.rb
224
225
  - lib/ccp/utils/colorize.rb
225
226
  - lib/ccp/utils/fixture_options.rb
@@ -243,7 +244,6 @@ files:
243
244
  - spec/kvs/core_spec.rb
244
245
  - spec/kvs/kvs_spec.rb
245
246
  - spec/kvs/lookup_spec.rb
246
- - spec/kvs/tch_spec.rb
247
247
  - spec/kvs/tokyo/cabinet_spec.rb
248
248
  - spec/kvs/tokyo/info_spec.rb
249
249
  - spec/models.rb
@@ -264,9 +264,10 @@ files:
264
264
  - spec/serializers/lookup_spec.rb
265
265
  - spec/serializers/serializer_spec.rb
266
266
  - spec/spec_helper.rb
267
+ - spec/storage/loadable_spec.rb
267
268
  homepage: http://github.com/maiha/ccp
268
- licenses: []
269
-
269
+ licenses:
270
+ - MIT
270
271
  post_install_message:
271
272
  rdoc_options: []
272
273
 
data/spec/kvs/tch_spec.rb DELETED
@@ -1,19 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- require 'spec_helper'
3
-
4
- __END__
5
-
6
- describe Ccp::Kvs::Tch do
7
- let(:kvs) { s = Ccp::Kvs::Tch.new; s.open(source); s }
8
- let(:tmp) { tmp_path + "kvs/tch" }
9
- before { FileUtils.rm_rf(tmp) if tmp.directory? }
10
-
11
- describe "#open" do
12
- subject { inform }
13
-
14
- context "foo.tch" do
15
- let(:source) { tmp + "foo.tch" }
16
- its(:path) { should == "" }
17
- end
18
- end
19
- end