knish 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
@@ -0,0 +1,3 @@
1
+ module Knish
2
+ VERSION = "0.2.6"
3
+ end
@@ -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
@@ -0,0 +1,7 @@
1
+ module ActiveModel
2
+ module Model
3
+ end
4
+
5
+ class Name < Struct.new(:klass, :namespace)
6
+ end
7
+ end
@@ -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