text-db 0.2.0.beta

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