text-db 0.2.0.beta

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in text-db.gemspec
4
+ gemspec
5
+
6
+ gem 'listen'
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Ondřej Moravčík
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,149 @@
1
+ # Textdb
2
+
3
+ Textdb is a database which structure is determined by folders and data are represented by files.
4
+
5
+ Current state: **beta version**.
6
+
7
+ Example:
8
+ ```ruby
9
+ # .
10
+ # |-- key1
11
+ # | |-- key1_1
12
+ # | | `-- value1_1_1.data
13
+ # | `-- value1_1.data
14
+ # `-- key2
15
+ # `-- value2_1.data
16
+
17
+ {
18
+ 'key1' => {
19
+ 'key1_1' => {
20
+ 'value1_1_1' => 'text'
21
+ },
22
+ 'value1_1_1' => 'text'
23
+ },
24
+ 'key2' => {
25
+ 'value2_1' => 'text'
26
+ }
27
+ }
28
+
29
+ ```
30
+
31
+ ## Installation
32
+
33
+ Add this line to your application's Gemfile:
34
+
35
+ ```
36
+ gem 'text-db'
37
+ ```
38
+
39
+ And then execute:
40
+
41
+ ```bash
42
+ $ bundle
43
+ ```
44
+
45
+ Or install it yourself as:
46
+
47
+ ```bash
48
+ $ gem install text-db
49
+ ```
50
+
51
+ ## Configuration
52
+
53
+ `Textdb.config` or `Textdb.configuration(&block)`.
54
+
55
+ How:
56
+ ```ruby
57
+ Textdb.configuration do
58
+ key "/tmp/1"
59
+ end
60
+
61
+ # --- OR ---
62
+
63
+ Textdb.config.key = "/tmp/1"
64
+ ```
65
+
66
+ <table>
67
+ <thead>
68
+ <tr>
69
+ <th>Key</th>
70
+ <th>Default</th>
71
+ <th>Description</th>
72
+ </tr>
73
+ </thead>
74
+
75
+ <tbody>
76
+ <tr>
77
+ <td><b>base_folder</b></td>
78
+ <td>/tmp/textdb</td>
79
+ <td>The root folder for Textdb. Folder must exist.</td>
80
+ </tr>
81
+ <tr>
82
+ <td><b>data_file_extension</b></td>
83
+ <td>.data</td>
84
+ <td>Extension for data files.</td>
85
+ </tr>
86
+ <tr>
87
+ <td><b>listen</b></td>
88
+ <td>false</td>
89
+ <td>
90
+ Automatic listening for changes in the root folder.<br>
91
+ <br>
92
+ Current works onyl with adding file.
93
+ </td>
94
+ </tr>
95
+ </tbody>
96
+ </table>
97
+
98
+ ## Usage
99
+
100
+ Folder structure:
101
+ ```
102
+ .
103
+ |-- key1
104
+ | |-- key1_1
105
+ | | `-- key1_1_1
106
+ | | |-- value1_1_1_1
107
+ | | `-- value1_1_1_2
108
+ | |-- value1_1
109
+ | `-- value1_2
110
+ `-- key2
111
+ `-- value2_1
112
+ ```
113
+
114
+ ### Read
115
+
116
+ ```ruby
117
+ Textdb.read { key1 } # -> list of all in the folder /key1
118
+ Textdb.read { key2.value2_1 } # -> content of file /key2/value2_1.data
119
+ ```
120
+
121
+ ### Create
122
+
123
+ ```ruby
124
+ Textdb.create { a.b.c } # -> create a file /a/b/c.data
125
+ Textdb.create { a.b.c }.update("text") # -> create a file /a/b/c.data with content "text"
126
+ ```
127
+
128
+ ### Update
129
+
130
+ `\n` is not included at the end.
131
+
132
+ ```ruby
133
+ Textdb.update("text") { a.b.c } # -> update /a/b/c.data with new content
134
+ ```
135
+
136
+ ### Delete
137
+
138
+ ```ruby
139
+ Textdb.delete { key1 } # -> delete everything in the folder /key1
140
+ Textdb.delete { key2.value2_1 } # -> delete only /key/value2_1.data
141
+ ```
142
+
143
+ ## Contributing
144
+
145
+ 1. Fork it
146
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
147
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
148
+ 4. Push to the branch (`git push origin my-new-feature`)
149
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new
5
+
6
+ task default: :spec
7
+ task test: :spec
@@ -0,0 +1,28 @@
1
+ module Textdb
2
+ class BlockMethod
3
+
4
+ instance_methods.each do |meth|
5
+ undef_method(meth) unless meth =~ /\A__/ || meth == :object_id || meth == :instance_eval
6
+ end
7
+
8
+ attr_reader :methods_seq
9
+
10
+ def self.get(&block)
11
+ begin
12
+ Textdb::BlockMethod.new.instance_eval(&block).methods_seq
13
+ rescue NoMethodError
14
+ []
15
+ end
16
+ end
17
+
18
+ def initialize
19
+ @methods_seq = []
20
+ end
21
+
22
+ def method_missing(method, *args, &block)
23
+ @methods_seq << method.to_s
24
+ self
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,50 @@
1
+ module Textdb
2
+ class Configuration
3
+
4
+ def initialize(config)
5
+ config.each do |key, value|
6
+ eval <<-METHOD
7
+ def #{key}(value = nil, &block)
8
+ if block_given?
9
+ @#{key}.instance_eval(&block)
10
+ end
11
+
12
+ if value.nil?
13
+ if @#{key}.is_a?(Proc)
14
+ return @#{key}.call
15
+ end
16
+ return @#{key}
17
+ end
18
+
19
+ self.#{key} = value
20
+ end
21
+ METHOD
22
+
23
+ if value.is_a?(Array)
24
+ eval <<-METHOD
25
+ def #{key}=(value)
26
+ @#{key} = value
27
+ #{value[1]}
28
+ value
29
+ end
30
+ METHOD
31
+
32
+ instance_variable_set :"@#{key}", value[0]
33
+ else
34
+ eval <<-METHOD
35
+ def #{key}=(value)
36
+ @#{key} = value
37
+ end
38
+ METHOD
39
+
40
+ instance_variable_set :"@#{key}", value
41
+ end
42
+
43
+ end
44
+
45
+
46
+
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,114 @@
1
+ module Textdb
2
+ module Data
3
+ class Key < Hash
4
+
5
+ attr_reader :full_path, :path, :name, :parent
6
+
7
+ def initialize(path, parent)
8
+ @full_path = File.join(Textdb.config.base_folder, path)
9
+ @path = path
10
+ @name = path.split('/')[-1]
11
+
12
+ @parent = parent
13
+
14
+ load_keys
15
+ load_values
16
+ end
17
+
18
+ def default(key)
19
+ raise Textdb::ExistError, "#{key} does not exist."
20
+ end
21
+
22
+
23
+
24
+ # Auto load
25
+ # -----------------------------------------------------------------
26
+ def keys_glob
27
+ File.join(@full_path, "*/")
28
+ end
29
+
30
+ def values_glob
31
+ File.join(@full_path, "*#{Textdb.config.data_file_extension}")
32
+ end
33
+
34
+ def load_keys
35
+ Dir.glob(keys_glob) do |f|
36
+ build_key(File.basename(f))
37
+ end
38
+ end
39
+
40
+ def load_values
41
+ Dir.glob(values_glob) do |f|
42
+ build_value(File.basename(f))
43
+ end
44
+ end
45
+
46
+
47
+
48
+ # Build and create
49
+ # -----------------------------------------------------------------
50
+ def build_key(name)
51
+ self[name] = Textdb::Data::Key.new(File.join(@path, name), self)
52
+ self[name]
53
+ end
54
+
55
+ def build_value(name)
56
+ name_without_ext = name.gsub(Textdb.config.data_file_extension, "")
57
+
58
+ self[name_without_ext] = Textdb::Data::Value.new(File.join(@path, name), self)
59
+ self[name_without_ext]
60
+ end
61
+
62
+ def create_key(name)
63
+ if Textdb.config.listen
64
+ Textdb::Event.listener.create_skip << File.join(@path, name)
65
+ end
66
+
67
+ Dir.mkdir(File.join(@full_path, name))
68
+
69
+ build_key(name)
70
+ end
71
+
72
+ def create_value(name)
73
+ name = "#{name}#{Textdb.config.data_file_extension}"
74
+
75
+ if Textdb.config.listen
76
+ Textdb::Event.listener.create_skip << File.join(@path, name)
77
+ end
78
+
79
+ File.open(File.join(@full_path, name), 'w') { |f| f.write('') }
80
+ build_value(name)
81
+ end
82
+
83
+ def show
84
+ self
85
+ end
86
+
87
+ # This method is available only in the Value class.
88
+ def update
89
+ raise Textdb::UpdateOnKey, "Key cannot be updated."
90
+ end
91
+
92
+ def destroy
93
+ self.each do |key, value|
94
+ # Value -> key representing name of the value
95
+ if key.is_a?(String)
96
+ value.destroy
97
+ else
98
+ key.destroy
99
+ end
100
+ end
101
+
102
+ begin
103
+ FileUtils.remove_entry_secure(@full_path)
104
+ parent.delete(@name)
105
+ rescue
106
+ return false
107
+ end
108
+
109
+ return true
110
+ end
111
+
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,50 @@
1
+ module Textdb
2
+ module Data
3
+ class Value
4
+
5
+ attr_reader :full_path, :path, :name, :parent
6
+
7
+ def initialize(path, parent)
8
+ @full_path = File.join(Textdb.config.base_folder, path)
9
+ @path = path
10
+ @name = path.split('/')[-1].gsub(Textdb.config.data_file_extension, '')
11
+
12
+ @parent = parent
13
+ end
14
+
15
+ # [] can be only in Key
16
+ def [](key)
17
+ raise Textdb::ValueCannotBeKey, "#{@name} is value."
18
+ end
19
+
20
+ def show
21
+ @data ||= show!
22
+ end
23
+
24
+ def show!
25
+ @data = File.read(@full_path)
26
+ end
27
+
28
+ def update(value)
29
+ File.open(@full_path, 'w') { |f| f.write(value) }
30
+ show!
31
+ end
32
+
33
+ def destroy
34
+ begin
35
+ File.delete(@full_path)
36
+ parent.delete(@name)
37
+ rescue
38
+ return false
39
+ end
40
+
41
+ return true
42
+ end
43
+
44
+ def inspect
45
+ %{#<Value::0x#{object_id} @data="#{@data}">}
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,8 @@
1
+ module Textdb
2
+ module Data
3
+
4
+ autoload :Key, 'textdb/data/key'
5
+ autoload :Value, 'textdb/data/value'
6
+
7
+ end
8
+ end
@@ -0,0 +1,11 @@
1
+ module Textdb
2
+
3
+ DEFAULT_CONFIGURATION = {
4
+ base_folder: ['/tmp/textdb', 'Textdb.rebuild'],
5
+
6
+ data_file_extension: ['.data', 'Textdb.rebuild'],
7
+
8
+ listen: [false, 'Textdb::Event.listener.change']
9
+ }
10
+
11
+ end
@@ -0,0 +1,18 @@
1
+ module Textdb
2
+
3
+ class ExistError < StandardError
4
+ end
5
+
6
+ class UpdateOnKey < StandardError
7
+ end
8
+
9
+ class ValueCannotBeKey < StandardError
10
+ end
11
+
12
+ class BlockRequired < StandardError
13
+ end
14
+
15
+ class AlreadyExist < StandardError
16
+ end
17
+
18
+ end
@@ -0,0 +1,59 @@
1
+ require "listen"
2
+
3
+ module Textdb
4
+ module Event
5
+ class Listener
6
+
7
+ attr_accessor :create_skip
8
+
9
+ def initialize
10
+ @create_skip = []
11
+ end
12
+
13
+ def config
14
+ Textdb.config
15
+ end
16
+
17
+ def change
18
+ if config.listen
19
+ start
20
+ else
21
+ stop
22
+ end
23
+ end
24
+
25
+ def start
26
+ @listener = Listen.to(config.base_folder)
27
+ .filter(filter)
28
+ .change(&callback)
29
+
30
+ @listener.start
31
+ end
32
+
33
+ def stop
34
+ @listener.stop
35
+ end
36
+
37
+
38
+
39
+ # Options for listen gem
40
+ # -----------------------------------------------------------------
41
+ def filter
42
+ /#{config.data_file_extension.gsub('.', '\.')}$/
43
+ end
44
+
45
+ def processor
46
+ Textdb::Event.processor
47
+ end
48
+
49
+ def callback
50
+ Proc.new do |modified, added, removed|
51
+ processor.create(added) unless added.empty?
52
+ processor.update(modified) unless modified.empty?
53
+ processor.delete(removed) unless removed.empty?
54
+ end
55
+ end
56
+
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,91 @@
1
+ module Textdb
2
+ module Event
3
+ class Processor
4
+
5
+ def initialize
6
+ end
7
+
8
+ def create(files)
9
+ puts "create: ---#{files}---"
10
+
11
+ files.each do |file|
12
+ pointer, value = get(file, true)
13
+ pointer.build_value(value)
14
+ end
15
+ end
16
+
17
+ def update(files)
18
+ puts "update: ---#{files}---"
19
+ end
20
+
21
+ def delete(files)
22
+ puts "delete: ---#{files}---"
23
+ end
24
+
25
+ def get(relative, create = false)
26
+ keys = relative.split('/')
27
+ value = keys.pop
28
+
29
+ pointer = Textdb.root
30
+ keys.each do |key|
31
+ begin
32
+ pointer = pointer[key]
33
+ rescue Textdb::ExistError
34
+ if create
35
+ pointer = pointer.build_key(key)
36
+ else
37
+ pointer[key]
38
+ end
39
+ end
40
+ end
41
+
42
+ return pointer, value
43
+ end
44
+
45
+ # def get(r, remove_ext = false)
46
+ # keys = r.split('/')
47
+ # last = keys.pop
48
+
49
+ # if remove_ext
50
+ # last = last.gsub(config.data_file_extension, '')
51
+ # end
52
+
53
+ # pointer = Textdb.root
54
+ # keys.each do |key|
55
+ # pointer = pointer[key]
56
+ # end
57
+
58
+ # return pointer, last
59
+ # end
60
+
61
+ # def create(b, r, t)
62
+ # pointer, last = get(r)
63
+
64
+ # unless @create_skip.delete('/' + r).nil?
65
+ # return pointer[last]
66
+ # end
67
+
68
+ # if t == :directory
69
+ # pointer.build_key(last)
70
+ # else
71
+ # pointer.build_value(last)
72
+ # end
73
+
74
+ # puts "create (directory: #{t == :directory ? "true " : "false"}): ---#{r}---"
75
+ # end
76
+
77
+ # def update(b, r, t)
78
+ # pointer, last = get(r, true)
79
+
80
+ # pointer[last].show!
81
+
82
+ # puts "update (directory: #{t == :directory ? "true " : "false"}): ---#{r}---"
83
+ # end
84
+
85
+ # def delete(b, r, t)
86
+ # puts "delete (directory: #{t == :directory ? "true " : "false"}): ---#{r}---"
87
+ # end
88
+
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,16 @@
1
+ module Textdb
2
+ module Event
3
+
4
+ autoload :Processor, 'textdb/event/processor'
5
+ autoload :Listener, 'textdb/event/listener'
6
+
7
+ def self.listener
8
+ @listener ||= Listener.new
9
+ end
10
+
11
+ def self.processor
12
+ @processor ||= Processor.new
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,3 @@
1
+ module Textdb
2
+ VERSION = "0.2.0.beta"
3
+ end
data/lib/textdb.rb ADDED
@@ -0,0 +1,99 @@
1
+ require "textdb/configuration"
2
+ require "textdb/default_configuration"
3
+ require "textdb/error"
4
+ require "textdb/version"
5
+
6
+ # TODO:
7
+ # - nicer method
8
+ # - check data file extension only at the end of name
9
+ # - documentation
10
+ # - unite textdb.* and event.processor.* methods
11
+
12
+ module Textdb
13
+
14
+ autoload :Data, 'textdb/data'
15
+ autoload :BlockMethod, 'textdb/block_method'
16
+ autoload :Event, 'textdb/event'
17
+
18
+
19
+
20
+ # Global
21
+ # -----------------------------------------------------------------
22
+ def self.config
23
+ @config ||= Textdb::Configuration.new(DEFAULT_CONFIGURATION)
24
+ end
25
+
26
+ def self.configure(&block)
27
+ config.instance_eval(&block)
28
+ end
29
+
30
+ def self.root
31
+ @root ||= Textdb::Data::Key.new('/', nil)
32
+ end
33
+
34
+ def self.rebuild
35
+ @root = nil
36
+ end
37
+
38
+
39
+
40
+ # Data
41
+ # -----------------------------------------------------------------
42
+ def self.get(&block)
43
+ unless block_given?
44
+ raise Textdb::BlockRequired, "This action require a block."
45
+ end
46
+
47
+ keys = Textdb::BlockMethod.get(&block)
48
+ pointer = root
49
+
50
+ keys.each do |key|
51
+ pointer = pointer[key.to_s]
52
+ end
53
+
54
+ pointer
55
+ end
56
+
57
+ def self.read(&block)
58
+ get(&block).show
59
+ end
60
+
61
+ def self.update(value, &block)
62
+ get(&block).update(value)
63
+ end
64
+
65
+ def self.destroy(&block)
66
+ get(&block).destroy
67
+ end
68
+
69
+ def self.delete(&block)
70
+ destroy(&block)
71
+ end
72
+
73
+ # TODO: Make the method nicer
74
+ def self.create(&block)
75
+ unless block_given?
76
+ raise Textdb::BlockRequired, "Creates action require a block."
77
+ end
78
+
79
+ keys = Textdb::BlockMethod.get(&block)
80
+ value = keys.pop
81
+ pointer = root
82
+
83
+ keys.each do |key|
84
+ begin
85
+ pointer = pointer[key]
86
+ rescue Textdb::ExistError
87
+ pointer = pointer.create_key(key)
88
+ end
89
+ end
90
+
91
+ begin
92
+ pointer = pointer[value]
93
+ raise Textdb::AlreadyExist, "#{value} already exist."
94
+ rescue Textdb::ExistError
95
+ pointer.create_value(value)
96
+ end
97
+ end
98
+
99
+ end
@@ -0,0 +1,46 @@
1
+ require "spec_helper"
2
+
3
+ describe Textdb::Configuration do
4
+ context "in line" do
5
+ let(:config) { Textdb.config }
6
+
7
+ it "should be OK" do
8
+ expect { config.base_folder = "/" }.to_not raise_error(NoMethodError)
9
+ end
10
+
11
+ it "should raise error" do
12
+ expect { config.abcdefghijkl = "/" }.to raise_error(NoMethodError)
13
+ end
14
+
15
+ it "should be updated" do
16
+ config.base_folder = "/abcdefghijkl"
17
+ expect(config.base_folder).to eql("/abcdefghijkl")
18
+ end
19
+ end
20
+
21
+ context "in DSL" do
22
+ it "should be OK" do
23
+ expect {
24
+ Textdb.configure do
25
+ base_folder "/"
26
+ end
27
+ }.to_not raise_error(NoMethodError)
28
+ end
29
+
30
+ it "should raise error" do
31
+ expect {
32
+ Textdb.configure do
33
+ abcdefghijkl "/"
34
+ end
35
+ }.to raise_error(NoMethodError)
36
+ end
37
+
38
+ it "should be updated" do
39
+ Textdb.configure do
40
+ base_folder "/abcdefghijkl"
41
+ end
42
+ expect(Textdb.configure { base_folder }).to eql("/abcdefghijkl")
43
+ end
44
+ end
45
+ end
46
+
@@ -0,0 +1,14 @@
1
+ require "spec_helper"
2
+
3
+ describe Textdb::BlockMethod do
4
+
5
+ let(:block) { Textdb::BlockMethod }
6
+
7
+ it "sequence of calling" do
8
+ expect( block.get { a.b.c } ).to eql(['a', 'b', 'c'])
9
+ end
10
+
11
+ it "empty block" do
12
+ expect( block.get { } ).to eql([])
13
+ end
14
+ end
@@ -0,0 +1,48 @@
1
+ require "spec_helper"
2
+
3
+ # .
4
+ # |-- key1
5
+ # | |-- key1_1
6
+ # | | `-- key1_1_1
7
+ # | | |-- value1_1_1_1
8
+ # | | `-- value1_1_1_2
9
+ # | |-- value1_1
10
+ # | `-- value1_2
11
+ # `-- key2
12
+ # `-- value2_1
13
+
14
+ describe "Textdb.create" do
15
+ before(:all) do
16
+ Textdb.config.base_folder = RSpec.configuration.dir
17
+ end
18
+
19
+ it "create keys" do
20
+ expect { Textdb.create { key1.key1_1.key1_1_1.value1_1_1_1 } }.to_not raise_error
21
+ expect { Textdb.create { key1.key1_1.key1_1_1.value1_1_1_2 } }.to_not raise_error
22
+ expect { Textdb.create { key1.value1_1 } }.to_not raise_error
23
+ expect { Textdb.create { key1.value1_2 } }.to_not raise_error
24
+ expect { Textdb.create { key2.value2_1 } }.to_not raise_error
25
+
26
+ list = Dir.glob(File.join(RSpec.configuration.dir, '**/*')).map { |x| x.gsub(RSpec.configuration.dir, '') }
27
+ expect(list).to eql(["/key1",
28
+ "/key1/value1_2#{Textdb.config.data_file_extension}",
29
+ "/key1/value1_1#{Textdb.config.data_file_extension}",
30
+ "/key1/key1_1",
31
+ "/key1/key1_1/key1_1_1",
32
+ "/key1/key1_1/key1_1_1/value1_1_1_1#{Textdb.config.data_file_extension}",
33
+ "/key1/key1_1/key1_1_1/value1_1_1_2#{Textdb.config.data_file_extension}",
34
+ "/key2",
35
+ "/key2/value2_1#{Textdb.config.data_file_extension}"])
36
+ end
37
+
38
+ it "require a block" do
39
+ expect { Textdb.create }.to raise_error(Textdb::BlockRequired)
40
+ end
41
+
42
+ context "listen for changes" do
43
+
44
+
45
+
46
+ end
47
+
48
+ end
@@ -0,0 +1,24 @@
1
+ require "spec_helper"
2
+
3
+ describe "Textdb.update" do
4
+ it "create with update" do
5
+ file = File.join RSpec.configuration.dir, "key3", "value3_1#{Textdb.config.data_file_extension}"
6
+
7
+ expect( File.exist?(file) ).to eql(false)
8
+
9
+ expect { Textdb.create{ key3.value3_1 }.update("text") }.to_not raise_error
10
+
11
+ expect( File.exist?(file) ).to eql(true)
12
+
13
+ expect( File.read(file) ).to eql("text")
14
+ end
15
+
16
+ it "update" do
17
+ file = File.join RSpec.configuration.dir, "key3", "value3_1#{Textdb.config.data_file_extension}"
18
+
19
+ Textdb.update("text 2") { key3.value3_1 }
20
+
21
+ expect( File.read(file) ).to eql("text 2")
22
+ end
23
+
24
+ end
@@ -0,0 +1,38 @@
1
+ require "spec_helper"
2
+
3
+ describe "Textdb.read" do
4
+ before(:all) do
5
+ Textdb.create{ key4.key4_1.value4_1_1 }.update("text 1")
6
+ Textdb.create{ key4.key4_1.value4_1_2 }.update("text 2")
7
+ Textdb.create{ key4.key4_1.value4_1_3 }.update("text 3")
8
+ Textdb.create{ key4.value4_1 }.update("text 4")
9
+ Textdb.create{ value1 }.update("text 5")
10
+ end
11
+
12
+ it "read before create" do
13
+ expect { Textdb.read { key4.key4_2.value4_2_1 } }.to raise_error(Textdb::ExistError)
14
+ end
15
+
16
+ it "read" do
17
+ expect( Textdb.read { key4.key4_1.value4_1_1 } ).to eql("text 1")
18
+ expect( Textdb.read { key4.key4_1.value4_1_2 } ).to eql("text 2")
19
+ expect( Textdb.read { key4.key4_1.value4_1_3 } ).to eql("text 3")
20
+ expect( Textdb.read { key4.value4_1 } ).to eql("text 4")
21
+ expect( Textdb.read { value1 } ).to eql("text 5")
22
+ end
23
+
24
+ it "file read" do
25
+ dir = Textdb.config.base_folder
26
+ ext = Textdb.config.data_file_extension
27
+
28
+ expect( File.read File.join(dir, "key4", "key4_1", "value4_1_1#{ext}") ).to eql("text 1")
29
+ expect( File.read File.join(dir, "key4", "key4_1", "value4_1_2#{ext}") ).to eql("text 2")
30
+ expect( File.read File.join(dir, "key4", "key4_1", "value4_1_3#{ext}") ).to eql("text 3")
31
+ expect( File.read File.join(dir, "key4", "value4_1#{ext}" ) ).to eql("text 4")
32
+ expect( File.read File.join(dir, "value1#{ext}" ) ).to eql("text 5")
33
+ end
34
+
35
+ it "without block" do
36
+ expect { Textdb.read }.to raise_error(Textdb::BlockRequired)
37
+ end
38
+ end
@@ -0,0 +1,48 @@
1
+ require "spec_helper"
2
+
3
+ describe "Textdb.delete" do
4
+ before(:all) do
5
+ Textdb.create { key5.key5_1.value5_1_1 }
6
+ Textdb.create { key5.key5_1.value5_1_2 }
7
+ Textdb.create { key5.key5_1.value5_1_3 }
8
+ Textdb.create { key5.value5_1 }
9
+ Textdb.create { value6 }
10
+ Textdb.create { key6.value6_1 }
11
+ end
12
+
13
+ it "value" do
14
+ file = File.join Textdb.config.base_folder, "key5", "key5_1", "value5_1_1#{Textdb.config.data_file_extension}"
15
+
16
+ expect( File.exist?(file) ).to eql(true)
17
+
18
+ Textdb.delete { key5.key5_1.value5_1_1 }
19
+
20
+ expect( File.exist?(file) ).to eql(false)
21
+
22
+ expect { Textdb.read { key5.key5_1.value5_1_1 } }.to raise_error(Textdb::ExistError)
23
+ end
24
+
25
+ it "key" do
26
+ dir = File.join Textdb.config.base_folder, "key6"
27
+
28
+ expect( Dir.exist?(dir) ).to eql(true)
29
+
30
+ Textdb.delete { key6 }
31
+
32
+ expect( Dir.exist?(dir) ).to eql(false)
33
+
34
+ expect { Textdb.read { key6 } }.to raise_error(Textdb::ExistError)
35
+ end
36
+
37
+ it "recursive" do
38
+ dir = File.join Textdb.config.base_folder, "key5"
39
+
40
+ Textdb.delete { key5 }
41
+
42
+ expect( Dir.exist?(dir) ).to eql(false)
43
+
44
+ expect { Textdb.read { key5.key5_1.value5_1_2 } }.to raise_error(Textdb::ExistError)
45
+ expect { Textdb.read { key5.key5_1.value5_1_3 } }.to raise_error(Textdb::ExistError)
46
+ expect { Textdb.read { key5.value5_1 } }.to raise_error(Textdb::ExistError)
47
+ end
48
+ end
@@ -0,0 +1,24 @@
1
+ $:.unshift File.dirname(__FILE__) + '/../lib'
2
+ require "tmpdir"
3
+ require "textdb"
4
+
5
+ RSpec.configure do |config|
6
+ config.treat_symbols_as_metadata_keys_with_true_values = true
7
+ config.run_all_when_everything_filtered = true
8
+ # config.filter_run :focus
9
+ config.color_enabled = true
10
+ config.formatter = 'documentation'
11
+
12
+
13
+
14
+ config.add_setting :dir
15
+
16
+ config.before(:suite) {
17
+ RSpec.configuration.dir = Dir.mktmpdir
18
+ Textdb.config.base_folder = RSpec.configuration.dir
19
+ Textdb.config.listen = true
20
+ }
21
+ config.after(:suite) {
22
+ FileUtils.remove_entry_secure RSpec.configuration.dir
23
+ }
24
+ end
data/text-db.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'textdb/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "text-db"
9
+ spec.version = Textdb::VERSION
10
+ spec.authors = ["Ondřej Moravčík"]
11
+ spec.email = ["moravcik.ondrej@gmail.com"]
12
+ spec.description = %q{Textdb is a database which structure is determined by folders and data are represented by files.}
13
+ spec.summary = %q{}
14
+ spec.homepage = "https://github.com/ondra-m/textdb"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files`.split($/)
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.3"
23
+ spec.add_development_dependency "rake"
24
+ spec.add_development_dependency "rspec"
25
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: text-db
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0.beta
5
+ prerelease: 6
6
+ platform: ruby
7
+ authors:
8
+ - Ondřej Moravčík
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-07-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: Textdb is a database which structure is determined by folders and data
63
+ are represented by files.
64
+ email:
65
+ - moravcik.ondrej@gmail.com
66
+ executables: []
67
+ extensions: []
68
+ extra_rdoc_files: []
69
+ files:
70
+ - .gitignore
71
+ - Gemfile
72
+ - LICENSE.txt
73
+ - README.md
74
+ - Rakefile
75
+ - lib/textdb.rb
76
+ - lib/textdb/block_method.rb
77
+ - lib/textdb/configuration.rb
78
+ - lib/textdb/data.rb
79
+ - lib/textdb/data/key.rb
80
+ - lib/textdb/data/value.rb
81
+ - lib/textdb/default_configuration.rb
82
+ - lib/textdb/error.rb
83
+ - lib/textdb/event.rb
84
+ - lib/textdb/event/listener.rb
85
+ - lib/textdb/event/processor.rb
86
+ - lib/textdb/version.rb
87
+ - spec/lib/01_configuration_spec.rb
88
+ - spec/lib/02_block_method_spec.rb
89
+ - spec/lib/03_create_spec.rb
90
+ - spec/lib/04_update_spec.rb
91
+ - spec/lib/05_read_spec.rb
92
+ - spec/lib/06_delete_spec.rb
93
+ - spec/spec_helper.rb
94
+ - text-db.gemspec
95
+ homepage: https://github.com/ondra-m/textdb
96
+ licenses:
97
+ - MIT
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ! '>='
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ! '>'
112
+ - !ruby/object:Gem::Version
113
+ version: 1.3.1
114
+ requirements: []
115
+ rubyforge_project:
116
+ rubygems_version: 1.8.23
117
+ signing_key:
118
+ specification_version: 3
119
+ summary: ''
120
+ test_files:
121
+ - spec/lib/01_configuration_spec.rb
122
+ - spec/lib/02_block_method_spec.rb
123
+ - spec/lib/03_create_spec.rb
124
+ - spec/lib/04_update_spec.rb
125
+ - spec/lib/05_read_spec.rb
126
+ - spec/lib/06_delete_spec.rb
127
+ - spec/spec_helper.rb
128
+ has_rdoc: