knish 0.2.6
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.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/knish.gemspec +25 -0
- data/lib/knish.rb +36 -0
- data/lib/knish/builder.rb +35 -0
- data/lib/knish/collection.rb +41 -0
- data/lib/knish/collection_config.rb +53 -0
- data/lib/knish/db_config.rb +29 -0
- data/lib/knish/delegate_inspector.rb +17 -0
- data/lib/knish/existing_models.rb +28 -0
- data/lib/knish/member.rb +31 -0
- data/lib/knish/model.rb +87 -0
- data/lib/knish/model_config.rb +51 -0
- data/lib/knish/reader.rb +47 -0
- data/lib/knish/version.rb +3 -0
- data/lib/knish/writer.rb +40 -0
- data/spec/builder_spec.rb +82 -0
- data/spec/collection_config_spec.rb +43 -0
- data/spec/collection_spec.rb +98 -0
- data/spec/fixtures/active_model_mock.rb +7 -0
- data/spec/knish_spec.rb +32 -0
- data/spec/model_config_spec.rb +54 -0
- data/spec/model_spec.rb +188 -0
- data/spec/reader_spec.rb +56 -0
- data/spec/spec_helper.rb +34 -0
- data/spec/support/file_helpers.rb +19 -0
- data/spec/support/model_classes.rb +32 -0
- data/spec/writer_spec.rb +59 -0
- metadata +132 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
module Knish
|
2
|
+
class ModelConfig < SimpleDelegator
|
3
|
+
attr_accessor :db_config, :path, :id, :omitted_namespace
|
4
|
+
attr_writer :data_attributes, :markdown_attributes, :collections
|
5
|
+
|
6
|
+
def initialize(db_config, path, id=nil)
|
7
|
+
super(db_config)
|
8
|
+
@path = path
|
9
|
+
@db_config = db_config
|
10
|
+
@id = id || next_id
|
11
|
+
end
|
12
|
+
|
13
|
+
def data_attributes
|
14
|
+
@data_attributes ||= []
|
15
|
+
end
|
16
|
+
|
17
|
+
def markdown_attributes
|
18
|
+
@markdown_attributes ||= []
|
19
|
+
end
|
20
|
+
|
21
|
+
def collections
|
22
|
+
@collections ||= []
|
23
|
+
end
|
24
|
+
|
25
|
+
def all_attributes
|
26
|
+
data_attributes + markdown_attributes
|
27
|
+
end
|
28
|
+
|
29
|
+
def collection_root
|
30
|
+
"#{db_config.db_root}/#{path}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def model_root
|
34
|
+
"#{collection_root}/#{id}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def next_id
|
38
|
+
ExistingModels.new(collection_root).next_id
|
39
|
+
end
|
40
|
+
|
41
|
+
def template_path
|
42
|
+
"#{view_to_db_path}/#{db_name}/#{path}/#{id}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def inspect
|
46
|
+
DelegateInspector.new(self,
|
47
|
+
[:db_config, :path, :id, :omitted_namespace, :data_attributes, :markdown_attributes, :collections]
|
48
|
+
).to_inspect
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/knish/reader.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
module Knish
|
2
|
+
class Reader
|
3
|
+
attr_reader :config
|
4
|
+
|
5
|
+
def initialize(config)
|
6
|
+
@config = config
|
7
|
+
end
|
8
|
+
|
9
|
+
def get_json
|
10
|
+
JSON.parse(read_file(config.data_filename) || '{}')
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_markdown
|
14
|
+
config.markdown_attributes.inject({}) do |hash, key|
|
15
|
+
hash[key] = read_markdown(key)
|
16
|
+
hash
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_collections
|
21
|
+
config.collections.inject({}) do |hash, collection_name|
|
22
|
+
collection = Collection.new(collection_name, config)
|
23
|
+
collection.load
|
24
|
+
hash[collection_name] = collection
|
25
|
+
hash
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def template(key)
|
30
|
+
"#{config.template_path}/#{key}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def persisted?
|
34
|
+
!!read_file(config.data_filename)
|
35
|
+
end
|
36
|
+
|
37
|
+
def read_file(filename)
|
38
|
+
File.read("#{config.model_root}/#{filename}") rescue nil
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def read_markdown(key)
|
44
|
+
read_file("_#{key}.md") || ""
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/knish/writer.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module Knish
|
2
|
+
class Writer
|
3
|
+
attr_reader :config
|
4
|
+
|
5
|
+
def initialize(config)
|
6
|
+
@config = config
|
7
|
+
end
|
8
|
+
|
9
|
+
def build_directories(directories)
|
10
|
+
make_root
|
11
|
+
directories.each {|dir| make_directory(dir) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def save_json(attributes)
|
15
|
+
make_root
|
16
|
+
write_file(config.data_filename, attributes.to_json)
|
17
|
+
end
|
18
|
+
|
19
|
+
def save_markdown(attributes)
|
20
|
+
make_root
|
21
|
+
attributes.each do |key, data|
|
22
|
+
write_file("_#{key}.md", data)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def write_file(filename, data)
|
29
|
+
File.open("#{config.model_root}/#{filename}", 'w') { |f| f.write(data) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def make_root
|
33
|
+
FileUtils.mkdir_p(config.model_root) unless File.exist?(config.model_root)
|
34
|
+
end
|
35
|
+
|
36
|
+
def make_directory(dir)
|
37
|
+
FileUtils.mkdir_p("#{config.model_root}/#{dir}") unless File.exist?("#{config.model_root}/#{dir}")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Knish, '.build' do
|
4
|
+
let(:config) { project_class.config }
|
5
|
+
|
6
|
+
context 'when all model level configuration is provided' do
|
7
|
+
let(:project_class) {
|
8
|
+
Project # defined in support
|
9
|
+
}
|
10
|
+
|
11
|
+
it 'builds a model class with the right attributes' do
|
12
|
+
expect(project_class.ancestors).to include(Knish::Model)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'has the right data in the model config' do
|
16
|
+
expect(config).to be_a(Knish::ModelConfig)
|
17
|
+
expect(config.path).to eq('projects')
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'adds the right class configuration attributes to the model class' do
|
21
|
+
expect(config.data_attributes).to eq(['name', 'url'])
|
22
|
+
expect(config.markdown_attributes).to eq(['description'])
|
23
|
+
expect(config.collections).to eq(['stories'])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'when some model level configuration is set' do
|
28
|
+
let(:project_class) {
|
29
|
+
Knish.build('projects') { |c| c.collections = ['features'] }
|
30
|
+
}
|
31
|
+
|
32
|
+
it 'sets missing model configuration to an empty array' do
|
33
|
+
expect(config.data_attributes).to eq([])
|
34
|
+
expect(config.markdown_attributes).to eq([])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'when setting db level configuration' do
|
39
|
+
let(:project_class) {
|
40
|
+
Knish.build('projects') do |config|
|
41
|
+
config.db_name = 'pizza'
|
42
|
+
config.data_attributes = ['name', 'url']
|
43
|
+
end
|
44
|
+
}
|
45
|
+
|
46
|
+
it 'updates the database related configuration' do
|
47
|
+
expect(config.db_name).to eq('pizza')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'when Knish already has custom global database configuration' do
|
52
|
+
let(:project_class) {
|
53
|
+
Knish.build('projects') do |config|
|
54
|
+
config.db_name = 'pizza'
|
55
|
+
config.data_attributes = ['name', 'url']
|
56
|
+
end
|
57
|
+
}
|
58
|
+
|
59
|
+
before do
|
60
|
+
Knish.configure do |config|
|
61
|
+
config.data_filename = 'json-data.json'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'does not mutate the Knish global configuration' do
|
66
|
+
expect(Knish.config.db_name).to_not eq('pizza')
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'model db configuration includes changes made at Knish level' do
|
70
|
+
expect(config.data_filename).to eq('json-data.json')
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'includes configured modifications to the db setup' do
|
74
|
+
expect(config.db_name).to eq('pizza')
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'uses model level configurations' do
|
78
|
+
expect(config.data_attributes).to eq(['name', 'url'])
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Knish::CollectionConfig do
|
4
|
+
let(:config) { Knish::CollectionConfig.new(model_config, path) }
|
5
|
+
let(:model_config) { Project.config }
|
6
|
+
let(:path) { 'stories' }
|
7
|
+
|
8
|
+
let(:project_path) { full_db_path + '/projects/1' }
|
9
|
+
let(:stories_path) { project_path + '/stories' }
|
10
|
+
|
11
|
+
before do
|
12
|
+
# setup file system of a collection
|
13
|
+
FileUtils.mkdir_p(project_path + "/stories/1")
|
14
|
+
File.open(project_path + "/data.json", 'w') {|f| f.write({name: 'hello project'}.to_json) }
|
15
|
+
File.open(project_path + "/stories/1/data.json", 'w') {|f| f.write({name: 'hello feature', ___type: 'Feature'}.to_json) }
|
16
|
+
end
|
17
|
+
|
18
|
+
after { clear_db(full_db_path) }
|
19
|
+
|
20
|
+
describe '#collection_root' do
|
21
|
+
it 'should be based on the model config and the path' do
|
22
|
+
expect(config.collection_root).to eq(stories_path)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#next_id' do
|
27
|
+
it 'should be the next available id' do
|
28
|
+
expect(config.next_id).to eq(2)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#memeber_config(klass, id)' do
|
33
|
+
let(:member_config) { config.member_config(Bug.config, 2) }
|
34
|
+
|
35
|
+
it 'should have the model attributes of the class' do
|
36
|
+
expect(member_config.all_attributes).to eq(Bug.config.all_attributes)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should have the path specific to this model' do
|
40
|
+
expect(member_config.model_root).to eq(project_path + "/stories/2")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Knish::Collection do
|
4
|
+
let(:collection) { Knish::Collection.new('stories', parent_config) }
|
5
|
+
let(:parent_config) { Knish::ModelConfig.new(fixture_db_config, 'projects') }
|
6
|
+
|
7
|
+
let(:model_class) {
|
8
|
+
Knish.build('features') do |config|
|
9
|
+
config.db_directory = db_fixture_path
|
10
|
+
config.data_attributes = ['name']
|
11
|
+
config.markdown_attributes = ['description']
|
12
|
+
end
|
13
|
+
}
|
14
|
+
|
15
|
+
describe '#add' do
|
16
|
+
let(:model) { model_class.new }
|
17
|
+
|
18
|
+
it 'puts the model in the collection' do
|
19
|
+
collection.add(model)
|
20
|
+
expect(collection.first).to eq(model)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'raises an error if the model is not a Knish object' do
|
24
|
+
expect{
|
25
|
+
collection.add({})
|
26
|
+
}.to raise_error
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'changes the configuration on the way in' do
|
30
|
+
collection.add(model)
|
31
|
+
expect(model.config.path).to eq('projects/1/stories')
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'when objects of that class already exist in the model configured location' do
|
35
|
+
let(:original_model_collection_path) { db_fixture_path + "/knish/features" }
|
36
|
+
|
37
|
+
before do
|
38
|
+
FileUtils.mkdir_p(original_model_collection_path + "/3")
|
39
|
+
end
|
40
|
+
|
41
|
+
after do
|
42
|
+
clear_db(db_fixture_path)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'reevaluates the id in the configuration' do
|
46
|
+
expect {
|
47
|
+
collection.add(model)
|
48
|
+
}.to change { model.config.id }
|
49
|
+
|
50
|
+
expect(collection.first.id).to eq(1)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '#save' do
|
56
|
+
let(:models) {
|
57
|
+
[model_class.new(name: 'bar'), model_class.new(name: 'foo')]
|
58
|
+
}
|
59
|
+
|
60
|
+
it 'calls save on each of the models' do
|
61
|
+
models.each do |m|
|
62
|
+
expect(m).to receive(:save)
|
63
|
+
collection.add(m)
|
64
|
+
end
|
65
|
+
collection.save
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '#load' do
|
70
|
+
before do
|
71
|
+
FileUtils.mkdir_p(collection.config.collection_root + "/1")
|
72
|
+
File.open(collection.config.collection_root + "/1/data.json", 'w') {|f| f.write({name: 'Hello', ___type: 'Feature'}.to_json) }
|
73
|
+
FileUtils.mkdir_p(collection.config.collection_root + "/2")
|
74
|
+
File.open(collection.config.collection_root + "/2/data.json", 'w') {|f| f.write({name: 'Goodbye', ___type: 'Bug'}.to_json) }
|
75
|
+
end
|
76
|
+
|
77
|
+
after { clear_db(db_fixture_path) }
|
78
|
+
|
79
|
+
it 'should be the right size' do
|
80
|
+
collection.load
|
81
|
+
expect(collection.size).to eq(2)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should remove existing models' do
|
85
|
+
project = Project.new(name: 'not for saving, thanks!')
|
86
|
+
collection << project
|
87
|
+
collection.load
|
88
|
+
expect(collection).not_to include(project)
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should build the right type of models for each' do
|
92
|
+
collection.load
|
93
|
+
|
94
|
+
expect(collection.first).to be_a(Feature)
|
95
|
+
expect(collection.last).to be_a(Bug)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/spec/knish_spec.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Knish, '.configure' do
|
4
|
+
it 'allows the configuration any values in the global config' do
|
5
|
+
Knish.configure do |config|
|
6
|
+
config.db_directory = db_fixture_path
|
7
|
+
config.view_to_db_path = 'view_to_db_path'
|
8
|
+
config.data_filename = 'my-data.json'
|
9
|
+
config.db_name = 'my-db'
|
10
|
+
end
|
11
|
+
|
12
|
+
expect(Knish.config.db_directory).to eq(db_fixture_path)
|
13
|
+
expect(Knish.config.view_to_db_path).to eq('view_to_db_path')
|
14
|
+
expect(Knish.config.data_filename).to eq('my-data.json')
|
15
|
+
expect(Knish.config.db_name).to eq('my-db')
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'uses a set of default values if not configured' do
|
19
|
+
expect(Knish.config.view_to_db_path).to eq('/../..')
|
20
|
+
expect(Knish.config.data_filename).to eq('data.json')
|
21
|
+
expect(Knish.config.db_name).to eq('knish')
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'constructs the database root from the db directory and the db name' do
|
25
|
+
Knish.configure do |config|
|
26
|
+
config.db_directory = 'db_dir'
|
27
|
+
config.db_name = 'my-db'
|
28
|
+
end
|
29
|
+
|
30
|
+
expect(Knish.config.db_root).to eq('db_dir/my-db')
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Knish::ModelConfig do
|
4
|
+
let(:config) { Knish::ModelConfig.new(fixture_db_config, 'projects') }
|
5
|
+
|
6
|
+
describe '#id' do
|
7
|
+
context 'when no id is passed in' do
|
8
|
+
it 'uses the next id' do
|
9
|
+
expect(config.id).to eq(config.next_id)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'when an id is given' do
|
14
|
+
let(:config) { Knish::ModelConfig.new(fixture_db_config, 'projects', 44) }
|
15
|
+
|
16
|
+
it 'uses it' do
|
17
|
+
expect(config.id).to eq(44)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#collection_root' do
|
23
|
+
it 'returns the collection root path' do
|
24
|
+
expect(config.collection_root).to eq(File.expand_path("#{db_fixture_path}/knish/projects"))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#next_id' do
|
29
|
+
before { clear_db(db_fixture_path) }
|
30
|
+
after { clear_db(db_fixture_path) }
|
31
|
+
|
32
|
+
context 'when there are no models in the collection' do
|
33
|
+
it 'returns 1' do
|
34
|
+
expect(config.next_id).to eq(1)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'when there are already models in the system' do
|
39
|
+
before { FileUtils.mkdir_p("#{config.collection_root}/1") }
|
40
|
+
|
41
|
+
it 'returns the next available id' do
|
42
|
+
expect(config.next_id).to eq(2)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'when a model is missing but was built' do
|
47
|
+
before { FileUtils.mkdir_p("#{config.collection_root}/2") }
|
48
|
+
|
49
|
+
it 'returns the next available id' do
|
50
|
+
expect(config.next_id).to eq(3)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|