io_shuten 0.0.1.dev5 → 0.0.3.dev1
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/.travis.yml +7 -0
- data/Gemfile +3 -4
- data/Gemfile.lock +2 -8
- data/README.md +17 -3
- data/Rakefile +25 -1
- data/benchmark/compare_mem_w_buf.rb +134 -0
- data/doc/IO_3A_3ABuffer.html +198 -0
- data/doc/IO_shuten/Base.html +349 -1943
- data/doc/IO_shuten/Buffer.html +1842 -0
- data/doc/IO_shuten/Errors/FileAccessError.html +5 -4
- data/doc/IO_shuten/Errors/FileNotFoundError.html +5 -4
- data/doc/IO_shuten/Errors/NodeExistsError.html +5 -4
- data/doc/IO_shuten/Errors/NodeNameError.html +5 -4
- data/doc/IO_shuten/Errors/NodeNotFoundError.html +5 -4
- data/doc/IO_shuten/Errors/NotYetImplemented.html +5 -4
- data/doc/IO_shuten/Errors.html +5 -4
- data/doc/IO_shuten/Memory.html +1798 -0
- data/doc/IO_shuten/Mongo.html +9 -13
- data/doc/IO_shuten/Redis.html +803 -8
- data/doc/IO_shuten/Stores/Mongo/Collection.html +5 -4
- data/doc/IO_shuten/Stores/Mongo/GridFS.html +5 -4
- data/doc/IO_shuten/Stores/Mongo.html +5 -4
- data/doc/IO_shuten/Stores/Redis/KeyValue.html +5 -4
- data/doc/IO_shuten/Stores/Redis/PubSub.html +5 -4
- data/doc/IO_shuten/Stores/Redis.html +5 -4
- data/doc/IO_shuten/Stores.html +5 -4
- data/doc/IO_shuten.html +7 -6
- data/doc/_index.html +20 -6
- data/doc/class_list.html +1 -1
- data/doc/file.README.html +21 -6
- data/doc/index.html +21 -6
- data/doc/method_list.html +119 -15
- data/doc/top-level-namespace.html +2 -2
- data/io_shuten.gemspec +16 -12
- data/lib/io_shuten/base.rb +1 -129
- data/lib/io_shuten/buffer.rb +156 -0
- data/lib/io_shuten/memory.rb +145 -0
- data/lib/io_shuten/redis.rb +65 -0
- data/lib/io_shuten/version.rb +1 -1
- data/lib/io_shuten.rb +2 -0
- data/spec/examples/logger_spec.rb +18 -2
- data/spec/lib/buffer_spec.rb +387 -0
- data/spec/lib/{base_spec.rb → memory_spec.rb} +92 -82
- data/spec/lib/mongo_spec.rb +1 -1
- data/spec/lib/redis_spec.rb +1 -1
- data/spec/spec_helper.rb +16 -12
- metadata +233 -163
@@ -96,9 +96,9 @@
|
|
96
96
|
</div>
|
97
97
|
|
98
98
|
<div id="footer">
|
99
|
-
Generated on
|
99
|
+
Generated on Thu Jan 26 00:45:41 2012 by
|
100
100
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
101
|
-
0.7.4 (ruby-1.
|
101
|
+
0.7.4 (ruby-1.8.7).
|
102
102
|
</div>
|
103
103
|
|
104
104
|
</body>
|
data/io_shuten.gemspec
CHANGED
@@ -5,12 +5,12 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "io_shuten"
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.3.dev1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Christoph Grabo"]
|
12
|
-
s.date = "2012-01-
|
13
|
-
s.description = "IO::shuten \
|
12
|
+
s.date = "2012-01-25"
|
13
|
+
s.description = "IO::shuten \342\200\223 Use databases as IO handler like you would do with files and streams."
|
14
14
|
s.email = ["chris@dinarrr.com"]
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE",
|
@@ -29,6 +29,8 @@ Gem::Specification.new do |s|
|
|
29
29
|
"LICENSE.de",
|
30
30
|
"README.md",
|
31
31
|
"Rakefile",
|
32
|
+
"benchmark/compare_mem_w_buf.rb",
|
33
|
+
"doc/IO_3A_3ABuffer.html",
|
32
34
|
"doc/IO_shuten.html",
|
33
35
|
"doc/IO_shuten/Base.html",
|
34
36
|
"doc/IO_shuten/Base/FileAccessError.html",
|
@@ -36,6 +38,7 @@ Gem::Specification.new do |s|
|
|
36
38
|
"doc/IO_shuten/Base/NodeNameError.html",
|
37
39
|
"doc/IO_shuten/Base/NodeNotFoundError.html",
|
38
40
|
"doc/IO_shuten/Base/NotYetImplemented.html",
|
41
|
+
"doc/IO_shuten/Buffer.html",
|
39
42
|
"doc/IO_shuten/Errors.html",
|
40
43
|
"doc/IO_shuten/Errors/FileAccessError.html",
|
41
44
|
"doc/IO_shuten/Errors/FileNotFoundError.html",
|
@@ -44,6 +47,7 @@ Gem::Specification.new do |s|
|
|
44
47
|
"doc/IO_shuten/Errors/NodeNameExistsError.html",
|
45
48
|
"doc/IO_shuten/Errors/NodeNotFoundError.html",
|
46
49
|
"doc/IO_shuten/Errors/NotYetImplemented.html",
|
50
|
+
"doc/IO_shuten/Memory.html",
|
47
51
|
"doc/IO_shuten/Mongo.html",
|
48
52
|
"doc/IO_shuten/Redis.html",
|
49
53
|
"doc/IO_shuten/Stores.html",
|
@@ -71,7 +75,9 @@ Gem::Specification.new do |s|
|
|
71
75
|
"io_shuten.gemspec",
|
72
76
|
"lib/io_shuten.rb",
|
73
77
|
"lib/io_shuten/base.rb",
|
78
|
+
"lib/io_shuten/buffer.rb",
|
74
79
|
"lib/io_shuten/errors.rb",
|
80
|
+
"lib/io_shuten/memory.rb",
|
75
81
|
"lib/io_shuten/mongo.rb",
|
76
82
|
"lib/io_shuten/redis.rb",
|
77
83
|
"lib/io_shuten/stores.rb",
|
@@ -83,7 +89,8 @@ Gem::Specification.new do |s|
|
|
83
89
|
"lib/io_shuten/stores/redis/pub_sub.rb",
|
84
90
|
"lib/io_shuten/version.rb",
|
85
91
|
"spec/examples/logger_spec.rb",
|
86
|
-
"spec/lib/
|
92
|
+
"spec/lib/buffer_spec.rb",
|
93
|
+
"spec/lib/memory_spec.rb",
|
87
94
|
"spec/lib/mongo_spec.rb",
|
88
95
|
"spec/lib/redis_spec.rb",
|
89
96
|
"spec/lib/stores/mongo/collection_spec.rb",
|
@@ -98,13 +105,14 @@ Gem::Specification.new do |s|
|
|
98
105
|
s.homepage = "http://github.com/asaaki/io_shuten"
|
99
106
|
s.licenses = ["MIT"]
|
100
107
|
s.require_paths = ["lib"]
|
101
|
-
s.rubygems_version = "1.8.
|
102
|
-
s.summary = "IO::shuten \
|
108
|
+
s.rubygems_version = "1.8.10"
|
109
|
+
s.summary = "IO::shuten \342\200\223 Use databases as IO handler. (NOT YET READY FOR PRODUCTION!)"
|
103
110
|
|
104
111
|
if s.respond_to? :specification_version then
|
105
112
|
s.specification_version = 3
|
106
113
|
|
107
114
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
115
|
+
s.add_runtime_dependency(%q<iobuffer>, ["~> 1.0.0"])
|
108
116
|
s.add_runtime_dependency(%q<hiredis>, ["~> 0.4.4"])
|
109
117
|
s.add_runtime_dependency(%q<redis>, ["~> 2.2.2"])
|
110
118
|
s.add_runtime_dependency(%q<bson_ext>, ["~> 1.5.2"])
|
@@ -116,12 +124,11 @@ Gem::Specification.new do |s|
|
|
116
124
|
s.add_development_dependency(%q<simplecov-rcov>, [">= 0"])
|
117
125
|
s.add_development_dependency(%q<simplecov-csv>, [">= 0"])
|
118
126
|
s.add_development_dependency(%q<redcarpet>, [">= 0"])
|
119
|
-
s.add_development_dependency(%q<rdoc>, [">= 0"])
|
120
127
|
s.add_development_dependency(%q<yard>, [">= 0"])
|
121
128
|
s.add_development_dependency(%q<yard-blame>, [">= 0"])
|
122
129
|
s.add_development_dependency(%q<pry>, [">= 0"])
|
123
|
-
s.add_development_dependency(%q<pry-doc>, [">= 0"])
|
124
130
|
else
|
131
|
+
s.add_dependency(%q<iobuffer>, ["~> 1.0.0"])
|
125
132
|
s.add_dependency(%q<hiredis>, ["~> 0.4.4"])
|
126
133
|
s.add_dependency(%q<redis>, ["~> 2.2.2"])
|
127
134
|
s.add_dependency(%q<bson_ext>, ["~> 1.5.2"])
|
@@ -133,13 +140,12 @@ Gem::Specification.new do |s|
|
|
133
140
|
s.add_dependency(%q<simplecov-rcov>, [">= 0"])
|
134
141
|
s.add_dependency(%q<simplecov-csv>, [">= 0"])
|
135
142
|
s.add_dependency(%q<redcarpet>, [">= 0"])
|
136
|
-
s.add_dependency(%q<rdoc>, [">= 0"])
|
137
143
|
s.add_dependency(%q<yard>, [">= 0"])
|
138
144
|
s.add_dependency(%q<yard-blame>, [">= 0"])
|
139
145
|
s.add_dependency(%q<pry>, [">= 0"])
|
140
|
-
s.add_dependency(%q<pry-doc>, [">= 0"])
|
141
146
|
end
|
142
147
|
else
|
148
|
+
s.add_dependency(%q<iobuffer>, ["~> 1.0.0"])
|
143
149
|
s.add_dependency(%q<hiredis>, ["~> 0.4.4"])
|
144
150
|
s.add_dependency(%q<redis>, ["~> 2.2.2"])
|
145
151
|
s.add_dependency(%q<bson_ext>, ["~> 1.5.2"])
|
@@ -151,11 +157,9 @@ Gem::Specification.new do |s|
|
|
151
157
|
s.add_dependency(%q<simplecov-rcov>, [">= 0"])
|
152
158
|
s.add_dependency(%q<simplecov-csv>, [">= 0"])
|
153
159
|
s.add_dependency(%q<redcarpet>, [">= 0"])
|
154
|
-
s.add_dependency(%q<rdoc>, [">= 0"])
|
155
160
|
s.add_dependency(%q<yard>, [">= 0"])
|
156
161
|
s.add_dependency(%q<yard-blame>, [">= 0"])
|
157
162
|
s.add_dependency(%q<pry>, [">= 0"])
|
158
|
-
s.add_dependency(%q<pry-doc>, [">= 0"])
|
159
163
|
end
|
160
164
|
end
|
161
165
|
|
data/lib/io_shuten/base.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
module IO_shuten
|
4
|
-
# IO_shuten::Base is
|
4
|
+
# IO_shuten::Base is interface class for other implementations.
|
5
5
|
class Base
|
6
6
|
|
7
7
|
# Storage of current Base instances of the running process
|
@@ -16,28 +16,6 @@ module IO_shuten
|
|
16
16
|
# @return [StringIO]
|
17
17
|
attr :container
|
18
18
|
|
19
|
-
# Creates a new Base node and stores it in the pool
|
20
|
-
#
|
21
|
-
# @param [String] node_name Name of the node node (container)
|
22
|
-
# @param [Symbol] node_name also a symbol is allowed
|
23
|
-
# @param *args (not used)
|
24
|
-
# @return [Base]
|
25
|
-
# @raise [NodeNameError]
|
26
|
-
def initialize(node_name = nil, *args)
|
27
|
-
if [String, Symbol].include?(node_name.class)
|
28
|
-
unless Base.instance_exists? node_name
|
29
|
-
@node_name = node_name
|
30
|
-
@container = StringIO.new("","w+")
|
31
|
-
|
32
|
-
@@instances << self unless @@instances.include?(self)
|
33
|
-
else
|
34
|
-
raise Errors::NodeExistsError, "Node already in pool, replacement is not allowed."
|
35
|
-
end
|
36
|
-
else
|
37
|
-
raise Errors::NodeNameError, "Name must be kind of String or Symbol and can't be nil."
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
19
|
### class methods
|
42
20
|
|
43
21
|
class << self
|
@@ -69,46 +47,6 @@ module IO_shuten
|
|
69
47
|
end
|
70
48
|
end
|
71
49
|
|
72
|
-
# Loads instances from disk
|
73
|
-
#
|
74
|
-
# @param [String] Directory name
|
75
|
-
# @param [Array] File names (HINT: you can provide a Dir.glob)
|
76
|
-
# @return [Boolean]
|
77
|
-
def load_instances source
|
78
|
-
case source.class.to_s
|
79
|
-
when "Array"
|
80
|
-
source.each do |file_name|
|
81
|
-
node = Base.new(file_name)
|
82
|
-
node.puts File.read(file_name)
|
83
|
-
end
|
84
|
-
when "String"
|
85
|
-
if File.exists?(source) && File.directory?(source)
|
86
|
-
Dir[source+"/**/*"].each do |file_name|
|
87
|
-
node = Base.new(file_name)
|
88
|
-
node.puts File.read(file_name)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
else
|
92
|
-
raise ArgumentError, "Input must be a kind of Array or String (but was: #{source.class})."
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
# Saves all instances to disk
|
97
|
-
#
|
98
|
-
# @return [Boolean]
|
99
|
-
def save_instances
|
100
|
-
results = @@instances.inject({}) do |result, node|
|
101
|
-
File.open(node.node_name,"w") do |fh|
|
102
|
-
fh.puts node.string
|
103
|
-
end
|
104
|
-
result[node.node_name] = :failed unless File.exists?(node.node_name)
|
105
|
-
end
|
106
|
-
if results
|
107
|
-
false
|
108
|
-
else
|
109
|
-
true
|
110
|
-
end
|
111
|
-
end
|
112
50
|
|
113
51
|
# Checks for existence of a node
|
114
52
|
#
|
@@ -123,76 +61,10 @@ module IO_shuten
|
|
123
61
|
alias_method :exists?, :instance_exists?
|
124
62
|
alias_method :exist?, :instance_exists?
|
125
63
|
|
126
|
-
# @return [Base] itself on success
|
127
|
-
# @raise [NodeNotFoundError]
|
128
|
-
def open node_name, *args
|
129
|
-
if Base.instance_exists? node_name
|
130
|
-
if block_given?
|
131
|
-
base = Base.send :load, node_name
|
132
|
-
base.reopen(base.container.string) if base.container.closed_write?
|
133
|
-
yield(base)
|
134
|
-
base.container.close_write
|
135
|
-
base
|
136
|
-
|
137
|
-
else
|
138
|
-
base = Base.send :load, node_name
|
139
|
-
base.reopen(base.container.string) if base.container.closed_write?
|
140
|
-
base
|
141
|
-
end
|
142
|
-
|
143
|
-
else
|
144
|
-
raise Errors::NodeNotFoundError
|
145
|
-
end
|
146
|
-
end
|
147
|
-
alias_method :open_node, :open
|
148
|
-
|
149
|
-
private
|
150
|
-
|
151
|
-
# @private
|
152
|
-
def load node_name
|
153
|
-
instances.select do |inst|
|
154
|
-
inst.node_name == node_name
|
155
|
-
end.first
|
156
|
-
end
|
157
|
-
alias_method :load_node, :load
|
158
|
-
|
159
64
|
end
|
160
65
|
|
161
66
|
### instance methods
|
162
67
|
|
163
|
-
# @return [Base] itself on success
|
164
|
-
# @raise [FileNotFoundError]
|
165
|
-
def load_from_file file_name = nil
|
166
|
-
file_name ||= self.node_name
|
167
|
-
if file_exists? file_name
|
168
|
-
self.container.string = File.read(file_name)
|
169
|
-
self
|
170
|
-
else
|
171
|
-
raise Errors::FileNotFoundError, self.node_name
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
# @return [Base] itself on success
|
176
|
-
# @raise [FileAccessError]
|
177
|
-
def save_to_file file_name = nil
|
178
|
-
file_name ||= self.node_name
|
179
|
-
begin
|
180
|
-
File.open(file_name, 'w') do |fh|
|
181
|
-
fh.write(self.container.string)
|
182
|
-
end
|
183
|
-
self
|
184
|
-
rescue Exception => e
|
185
|
-
raise Errors::FileAccessError, "Reason: #{e.message}"
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
# @return [Boolean]
|
190
|
-
def file_exists? file_name = nil
|
191
|
-
file_name ||= self.node_name
|
192
|
-
File.exists?(file_name)
|
193
|
-
end
|
194
|
-
alias_method :file_exist?, :file_exists?
|
195
|
-
|
196
68
|
# @private
|
197
69
|
def respond_to? sym
|
198
70
|
!!self.methods.include?(sym) || respond_to_missing?(sym)
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "iobuffer"
|
4
|
+
|
5
|
+
# @private
|
6
|
+
class ::IO::Buffer
|
7
|
+
def close; end #dummy
|
8
|
+
end
|
9
|
+
|
10
|
+
module IO_shuten
|
11
|
+
# Implementation of the Buffer storage
|
12
|
+
class Buffer < IO_shuten::Base
|
13
|
+
|
14
|
+
# Creates a new Buffer node and stores it in the pool
|
15
|
+
#
|
16
|
+
# @param [String] node_name Name of the node node (container)
|
17
|
+
# @param [Symbol] node_name also a symbol is allowed
|
18
|
+
# @return [Buffer]
|
19
|
+
# @raise [NodeNameError]
|
20
|
+
def initialize(node_name = nil)
|
21
|
+
if [String, Symbol].include?(node_name.class)
|
22
|
+
unless Buffer.instance_exists? node_name
|
23
|
+
@node_name = node_name
|
24
|
+
@container = ::IO::Buffer.new
|
25
|
+
|
26
|
+
@@instances << self unless @@instances.include?(self)
|
27
|
+
else
|
28
|
+
raise Errors::NodeExistsError, "Node already in pool, replacement is not allowed."
|
29
|
+
end
|
30
|
+
else
|
31
|
+
raise Errors::NodeNameError, "Name must be kind of String or Symbol and can't be nil."
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
### class methods
|
36
|
+
|
37
|
+
class << self
|
38
|
+
|
39
|
+
# Loads instances from disk
|
40
|
+
#
|
41
|
+
# @param [String] Directory name
|
42
|
+
# @param [Array] File names (HINT: you can provide a Dir.glob)
|
43
|
+
# @return [Boolean]
|
44
|
+
def load_instances source
|
45
|
+
case source.class.to_s
|
46
|
+
when "Array"
|
47
|
+
source.each do |file_name|
|
48
|
+
node = Buffer.new(file_name)
|
49
|
+
File.open(file_name,'r') do |fh|
|
50
|
+
node.read_from fh
|
51
|
+
end
|
52
|
+
end
|
53
|
+
when "String"
|
54
|
+
if File.exists?(source) && File.directory?(source)
|
55
|
+
Dir[source+"/**/*"].each do |file_name|
|
56
|
+
node = Buffer.new(file_name)
|
57
|
+
File.open(file_name,'r') do |fh|
|
58
|
+
node.read_from fh
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
else
|
63
|
+
raise ArgumentError, "Input must be a kind of Array or String (but was: #{source.class})."
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Saves all instances to disk
|
68
|
+
#
|
69
|
+
# @return [Boolean]
|
70
|
+
def save_instances
|
71
|
+
results = instances.inject({}) do |result, node|
|
72
|
+
File.open(node.node_name,"w") do |fh|
|
73
|
+
node.write_to(fh)
|
74
|
+
end
|
75
|
+
|
76
|
+
result[node.node_name] = :failed unless File.exists?(node.node_name)
|
77
|
+
end
|
78
|
+
if results
|
79
|
+
false
|
80
|
+
else
|
81
|
+
true
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# @return [Buffer] itself on success
|
86
|
+
# @raise [NodeNotFoundError]
|
87
|
+
def open node_name, *args
|
88
|
+
if Buffer.instance_exists? node_name
|
89
|
+
if block_given?
|
90
|
+
base = Buffer.send :load, node_name
|
91
|
+
yield(base)
|
92
|
+
base
|
93
|
+
|
94
|
+
else
|
95
|
+
base = Buffer.send :load, node_name
|
96
|
+
base
|
97
|
+
end
|
98
|
+
|
99
|
+
else
|
100
|
+
raise Errors::NodeNotFoundError
|
101
|
+
end
|
102
|
+
end
|
103
|
+
alias_method :open_node, :open
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
# @private
|
108
|
+
def load node_name
|
109
|
+
instances.select do |inst|
|
110
|
+
inst.node_name == node_name
|
111
|
+
end.first
|
112
|
+
end
|
113
|
+
alias_method :load_node, :load
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
### instance methods
|
118
|
+
|
119
|
+
# @return [Buffer] itself on success
|
120
|
+
# @raise [FileNotFoundError]
|
121
|
+
def load_from_file file_name = nil
|
122
|
+
file_name ||= self.node_name
|
123
|
+
if file_exists? file_name
|
124
|
+
File.open(file_name) do |fh|
|
125
|
+
self.container.read_from(fh)
|
126
|
+
end
|
127
|
+
self
|
128
|
+
else
|
129
|
+
raise Errors::FileNotFoundError, self.node_name
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# @return [Buffer] itself on success
|
134
|
+
# @raise [FileAccessError]
|
135
|
+
def save_to_file file_name = nil
|
136
|
+
file_name ||= self.node_name
|
137
|
+
begin
|
138
|
+
File.open(file_name, 'w') do |fh|
|
139
|
+
self.container.write_to(fh)
|
140
|
+
end
|
141
|
+
self
|
142
|
+
rescue Exception => e
|
143
|
+
raise Errors::FileAccessError, "Reason: #{e.message}"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# @return [Boolean]
|
148
|
+
def file_exists? file_name = nil
|
149
|
+
file_name ||= self.node_name
|
150
|
+
File.exists?(file_name)
|
151
|
+
end
|
152
|
+
alias_method :file_exist?, :file_exists?
|
153
|
+
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module IO_shuten
|
4
|
+
# Implementation of the Memory storage
|
5
|
+
class Memory < IO_shuten::Base
|
6
|
+
|
7
|
+
# Creates a new Memory node and stores it in the pool
|
8
|
+
#
|
9
|
+
# @param [String] node_name Name of the node node (container)
|
10
|
+
# @param [Symbol] node_name also a symbol is allowed
|
11
|
+
# @return [Memory]
|
12
|
+
# @raise [NodeNameError]
|
13
|
+
def initialize(node_name = nil)
|
14
|
+
if [String, Symbol].include?(node_name.class)
|
15
|
+
unless Memory.instance_exists? node_name
|
16
|
+
@node_name = node_name
|
17
|
+
@container = ::StringIO.new("","w+")
|
18
|
+
|
19
|
+
@@instances << self unless @@instances.include?(self)
|
20
|
+
else
|
21
|
+
raise Errors::NodeExistsError, "Node already in pool, replacement is not allowed."
|
22
|
+
end
|
23
|
+
else
|
24
|
+
raise Errors::NodeNameError, "Name must be kind of String or Symbol and can't be nil."
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
### class methods
|
29
|
+
|
30
|
+
class << self
|
31
|
+
|
32
|
+
# Loads instances from disk
|
33
|
+
#
|
34
|
+
# @param [String] Directory name
|
35
|
+
# @param [Array] File names (HINT: you can provide a Dir.glob)
|
36
|
+
# @return [Boolean]
|
37
|
+
def load_instances source
|
38
|
+
case source.class.to_s
|
39
|
+
when "Array"
|
40
|
+
source.each do |file_name|
|
41
|
+
node = Memory.new(file_name)
|
42
|
+
node.puts File.read(file_name)
|
43
|
+
end
|
44
|
+
when "String"
|
45
|
+
if File.exists?(source) && File.directory?(source)
|
46
|
+
Dir[source+"/**/*"].each do |file_name|
|
47
|
+
node = Memory.new(file_name)
|
48
|
+
node.puts File.read(file_name)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
else
|
52
|
+
raise ArgumentError, "Input must be a kind of Array or String (but was: #{source.class})."
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Saves all instances to disk
|
57
|
+
#
|
58
|
+
# @return [Boolean]
|
59
|
+
def save_instances
|
60
|
+
results = instances.inject({}) do |result, node|
|
61
|
+
File.open(node.node_name,"w") do |fh|
|
62
|
+
fh.puts node.string
|
63
|
+
end
|
64
|
+
result[node.node_name] = :failed unless File.exists?(node.node_name)
|
65
|
+
end
|
66
|
+
if results
|
67
|
+
false
|
68
|
+
else
|
69
|
+
true
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# @return [Memory] itself on success
|
74
|
+
# @raise [NodeNotFoundError]
|
75
|
+
def open node_name, *args
|
76
|
+
if Memory.instance_exists? node_name
|
77
|
+
if block_given?
|
78
|
+
base = Memory.send :load, node_name
|
79
|
+
base.reopen(base.container.string) if base.container.closed_write?
|
80
|
+
yield(base)
|
81
|
+
base.container.close_write
|
82
|
+
base
|
83
|
+
|
84
|
+
else
|
85
|
+
base = Memory.send :load, node_name
|
86
|
+
base.reopen(base.container.string) if base.container.closed_write?
|
87
|
+
base
|
88
|
+
end
|
89
|
+
|
90
|
+
else
|
91
|
+
raise Errors::NodeNotFoundError
|
92
|
+
end
|
93
|
+
end
|
94
|
+
alias_method :open_node, :open
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
# @private
|
99
|
+
def load node_name
|
100
|
+
instances.select do |inst|
|
101
|
+
inst.node_name == node_name
|
102
|
+
end.first
|
103
|
+
end
|
104
|
+
alias_method :load_node, :load
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
### instance methods
|
109
|
+
|
110
|
+
# @return [Memory] itself on success
|
111
|
+
# @raise [FileNotFoundError]
|
112
|
+
def load_from_file file_name = nil
|
113
|
+
file_name ||= self.node_name
|
114
|
+
if file_exists? file_name
|
115
|
+
self.container.string = File.read(file_name)
|
116
|
+
self
|
117
|
+
else
|
118
|
+
raise Errors::FileNotFoundError, self.node_name
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# @return [Memory] itself on success
|
123
|
+
# @raise [FileAccessError]
|
124
|
+
def save_to_file file_name = nil
|
125
|
+
file_name ||= self.node_name
|
126
|
+
begin
|
127
|
+
File.open(file_name, 'w') do |fh|
|
128
|
+
fh.write(self.container.string)
|
129
|
+
end
|
130
|
+
self
|
131
|
+
rescue Exception => e
|
132
|
+
raise Errors::FileAccessError, "Reason: #{e.message}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# @return [Boolean]
|
137
|
+
def file_exists? file_name = nil
|
138
|
+
file_name ||= self.node_name
|
139
|
+
File.exists?(file_name)
|
140
|
+
end
|
141
|
+
alias_method :file_exist?, :file_exists?
|
142
|
+
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
data/lib/io_shuten/redis.rb
CHANGED
@@ -1,10 +1,75 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
require "redis"
|
4
|
+
|
3
5
|
module IO_shuten
|
4
6
|
# Implementation of the Redis storage
|
5
7
|
#
|
8
|
+
# Two backends are possible: simple key-value and pub-sub messaging
|
9
|
+
#
|
10
|
+
# KeyValue
|
11
|
+
# has different node types.
|
12
|
+
# Incremental single message store: each write will create a new key.
|
13
|
+
# Message collection store: all writes go to a single key.
|
14
|
+
# Good for events or logs.
|
15
|
+
#
|
16
|
+
# PubSub
|
17
|
+
# has different node types: publisher and subscriber.
|
18
|
+
# In future maybe a combined publisher-subscriber type possible, but in general less needed.
|
19
|
+
# Good for live event messaging.
|
20
|
+
#
|
6
21
|
# @todo Needs two backends (default database interface and pub/sub interface)!
|
7
22
|
class Redis < IO_shuten::Base
|
8
23
|
|
24
|
+
# Global redis client instance for the pool
|
25
|
+
# @return [Object] Redis instance
|
26
|
+
@@redis = ::Redis.new
|
27
|
+
|
28
|
+
# @param [String] node_name
|
29
|
+
# @param [Symbol] node_name
|
30
|
+
# @param [Symbol] backend :key_value, :pub_sub
|
31
|
+
# @param [Symbol] type for backend :key_value => [:single,:collection], for backend :pub_sub => [:publisher,:subscriber]
|
32
|
+
# @param [Object] Redis an instance for this specific node, otherwise the Redis.redis instance will be used
|
33
|
+
def initialize node_name, backend, type, redis_instance = nil
|
34
|
+
# based on the backend type it should instantiate the corresponding backend store module
|
35
|
+
node = :nil
|
36
|
+
case backend
|
37
|
+
when :key_value
|
38
|
+
Stores::Redis::KeyValue #.create(type)
|
39
|
+
when :pub_sub
|
40
|
+
Stores::Redis::PubSub #.create(type)
|
41
|
+
else
|
42
|
+
raise ArgumentError, "Backend type unknown. Use :key_value or :pub_sub"
|
43
|
+
end
|
44
|
+
@@instances << node
|
45
|
+
end
|
46
|
+
|
47
|
+
### class methods ###
|
48
|
+
|
49
|
+
class << self
|
50
|
+
|
51
|
+
# @return [Object] current redis client
|
52
|
+
def redis
|
53
|
+
@@redis
|
54
|
+
end
|
55
|
+
|
56
|
+
# Sets a new global redis client for the pool
|
57
|
+
# @return [Object] new redis client
|
58
|
+
def redis= new_redis
|
59
|
+
@redis = new_redis
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
### instance methods ###
|
64
|
+
|
65
|
+
def read
|
66
|
+
end
|
67
|
+
|
68
|
+
def write
|
69
|
+
end
|
70
|
+
|
71
|
+
def close
|
72
|
+
end
|
73
|
+
|
9
74
|
end
|
10
75
|
end
|
data/lib/io_shuten/version.rb
CHANGED