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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9cebed317cbe29913edc52b2b410aac9b62033a3
4
+ data.tar.gz: bf914734271075a48d16cd03c9be1342418fd8d6
5
+ SHA512:
6
+ metadata.gz: 644bd7a99649f92ceed6d6cd12dbfe97f60583454ceb947650bf3d5ee736fe219c15cdaac30956109879d08ad0bbd22a54f953d6ecccde60ff6ec8bd6908cf34
7
+ data.tar.gz: 3be97cd34a43e957c176c3faac8670919791ea0a9378e11de2961851a90c0adc18d31602e2b400d3ac09a538e38a045bfddf094591ab7a42b94edbac006ec937
@@ -0,0 +1,22 @@
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
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in knish.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Kane Baccigalupi
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.
@@ -0,0 +1,29 @@
1
+ # Knish
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'knish'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install knish
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( https://github.com/[my-github-username]/knish/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'knish/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "knish"
8
+ spec.version = Knish::VERSION
9
+ spec.authors = ["Kane Baccigalupi"]
10
+ spec.email = ["baccigalupi@gmail.com"]
11
+ spec.summary = %q{File backed data models, excellent for CMS apps!}
12
+ spec.description = %q{The problem with CMSs is that you really want your application content in source control,
13
+ not a database. Knish provides a structured data model for saving data to json, and formatted html to markdown}
14
+ spec.homepage = "http://github.com/baccigalupi/knish"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0")
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.6"
23
+ spec.add_development_dependency "rake"
24
+ spec.add_development_dependency "rspec"
25
+ end
@@ -0,0 +1,36 @@
1
+ require 'json'
2
+ require 'forwardable'
3
+ require 'delegate'
4
+ require 'fileutils'
5
+
6
+ require "knish/version"
7
+ require "knish/delegate_inspector"
8
+ require "knish/existing_models"
9
+ require "knish/db_config"
10
+ require "knish/model_config"
11
+ require "knish/writer"
12
+ require "knish/reader"
13
+ require "knish/builder"
14
+ require "knish/model"
15
+ require "knish/collection"
16
+ require "knish/collection_config"
17
+ require "knish/member"
18
+
19
+ module Knish
20
+ def self.clear_config
21
+ @config = nil
22
+ end
23
+
24
+ def self.config
25
+ @config ||= DbConfig.new
26
+ end
27
+
28
+ def self.configure(&block)
29
+ block.call(config)
30
+ end
31
+
32
+ def self.build(path, &block)
33
+ builder = Builder.new(path, &block)
34
+ builder.make_model
35
+ end
36
+ end
@@ -0,0 +1,35 @@
1
+ module Knish
2
+ class Builder
3
+ attr_reader :collection_name, :block
4
+
5
+ def initialize(collection_name, &block)
6
+ @collection_name = collection_name
7
+ @block = block
8
+ end
9
+
10
+ def make_model
11
+ klass = Class.new(Model)
12
+ klass.config = config
13
+ klass.send(:attr_accessor, *config.all_attributes)
14
+ klass.send(:attr_writer, *config.collections)
15
+ add_collections(klass, config.collections)
16
+ klass
17
+ end
18
+
19
+ def add_collections(klass, collections)
20
+ collections.each do |collection|
21
+ klass.class_eval <<-RUBY, __FILE__, __LINE__
22
+ def #{collection}
23
+ @#{collection} ||= Collection.new('#{collection}', config)
24
+ end
25
+ RUBY
26
+ end
27
+ end
28
+
29
+ def config
30
+ model_config = ModelConfig.new(Knish.config.clone, collection_name)
31
+ block.call(model_config)
32
+ model_config
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,41 @@
1
+ module Knish
2
+ class Collection < SimpleDelegator
3
+ attr_reader :name, :config
4
+
5
+ def initialize(name, parent_config)
6
+ super([])
7
+ @name = name
8
+ @config = CollectionConfig.new(parent_config, name)
9
+ end
10
+
11
+ def add(model)
12
+ configure(model)
13
+ push(model)
14
+ end
15
+
16
+ alias :<< :add
17
+
18
+ def save
19
+ each(&:save)
20
+ end
21
+
22
+ def load
23
+ clear
24
+ config.generic_model_configs.each do |c|
25
+ push(
26
+ Member.new(config, c).loaded_model
27
+ )
28
+ end
29
+ self
30
+ end
31
+
32
+ def next_id
33
+ config.next_id + select{|m| !m.persisted? }.size
34
+ end
35
+
36
+ def configure(model)
37
+ model.config = config.member_config(model.config)
38
+ model
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,53 @@
1
+ module Knish
2
+ class CollectionConfig < SimpleDelegator
3
+ attr_accessor :db_config, :path, :model_config, :unpersisted_count
4
+
5
+ def initialize(model_config, path)
6
+ super(model_config.db_config)
7
+ @path = path
8
+ @db_config = model_config.db_config
9
+ @model_config = model_config
10
+ @unpersisted_count = 0
11
+ end
12
+
13
+ def collection_root
14
+ "#{model_config.model_root}/#{path}"
15
+ end
16
+
17
+ def next_id
18
+ ExistingModels.new(collection_root).next_id + unpersisted_count
19
+ end
20
+
21
+ def generic_model_configs
22
+ ExistingModels.new(collection_root).ids.map { |id| member_config(generic_config, id) }
23
+ end
24
+
25
+ def generic_config
26
+ ModelConfig.new(Knish.config, '')
27
+ end
28
+
29
+ def inspect
30
+ DelegateInspector.new(self,
31
+ [:db_config, :model_config, :path]
32
+ ).to_inspect
33
+ end
34
+
35
+ def member_config(original_config, id=nil)
36
+ config = original_config.clone
37
+ config.id = member_id(id)
38
+ config.path = "#{model_config.path}/#{model_config.id}/#{path}"
39
+ config
40
+ end
41
+
42
+ private
43
+
44
+ def member_id(id)
45
+ return id if id
46
+ id = next_id
47
+ self.unpersisted_count += 1
48
+ id
49
+ end
50
+
51
+ end
52
+ end
53
+
@@ -0,0 +1,29 @@
1
+ module Knish
2
+ class DbConfig
3
+ attr_writer :db_directory, :view_to_db_path, :data_filename, :db_name
4
+
5
+ def db_directory
6
+ @db_directory ||= `pwd`.chomp
7
+ end
8
+
9
+ def db_root
10
+ "#{db_directory}/#{db_name}"
11
+ end
12
+
13
+ def db_name
14
+ @db_name ||= 'knish'
15
+ end
16
+
17
+ def view_to_db_path
18
+ @view_to_db_path ||= '/../..'
19
+ end
20
+
21
+ def data_filename
22
+ @data_filename ||= 'data.json'
23
+ end
24
+
25
+ def type_key
26
+ '___type'
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,17 @@
1
+ module Knish
2
+ class DelegateInspector < Struct.new(:object, :attributes)
3
+ def to_inspect
4
+ "#<#{object.class.name}:#{memory_location} #{mapped_attributes.join(' ')}>"
5
+ end
6
+
7
+ def memory_location
8
+ '0x00%x' % (object.object_id << 1)
9
+ end
10
+
11
+ def mapped_attributes
12
+ attributes.map do |attr|
13
+ "@#{attr}=#{object.send(attr).inspect}"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,28 @@
1
+ module Knish
2
+ class ExistingModels < Struct.new(:path)
3
+ def next_id
4
+ (ids.max || 0) + 1
5
+ end
6
+
7
+ def ids
8
+ paths.map{|path| id(path) }.compact
9
+ end
10
+
11
+ def paths
12
+ Dir.glob("#{path}/*")
13
+ end
14
+
15
+ def data
16
+ paths.map { |path|
17
+ Data.new(id(path), path) if id(path)
18
+ }.compact
19
+ end
20
+
21
+ def id(path)
22
+ last = path.split('/').last
23
+ last && last.to_i
24
+ end
25
+
26
+ Data = Struct.new(:id, :path)
27
+ end
28
+ end
@@ -0,0 +1,31 @@
1
+ module Knish
2
+ class Member < Struct.new(:collection_config, :config)
3
+ def model
4
+ return @model if @model
5
+ @model = model_class.new(id: config.id)
6
+ @model.config = collection_config.member_config(@model.config, config.id)
7
+ @model
8
+ end
9
+
10
+ def loaded_model
11
+ model.load
12
+ model
13
+ end
14
+
15
+ def class_name
16
+ data[config.type_key]
17
+ end
18
+
19
+ def model_class
20
+ class_name && eval(class_name)
21
+ end
22
+
23
+ def data
24
+ @data ||= reader.get_json
25
+ end
26
+
27
+ def reader
28
+ Reader.new(config)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,87 @@
1
+ module Knish
2
+ class Model
3
+ if defined?(ActiveModel::Model)
4
+ include ActiveModel::Model
5
+
6
+ def self.model_name
7
+ ActiveModel::Name.new(self, omitted_namespace)
8
+ end
9
+ end
10
+
11
+ attr_writer :config
12
+
13
+ def initialize(attrs=nil)
14
+ attrs ||= {}
15
+ set(attrs)
16
+ end
17
+
18
+ extend Forwardable
19
+
20
+ def_delegators :config, :id, :id=
21
+ def_delegators :reader, :persisted?
22
+
23
+ def save
24
+ writer.save_json(data_attributes)
25
+ writer.save_markdown(markdown_attributes)
26
+ true
27
+ end
28
+
29
+ def load
30
+ set(reader.get_json)
31
+ set(reader.get_markdown)
32
+ true
33
+ end
34
+
35
+ def set(attrs)
36
+ attrs.each do |key, value|
37
+ next if key.to_sym == config.type_key.to_sym
38
+ public_send("#{key}=", value)
39
+ end
40
+ end
41
+
42
+ def template(key)
43
+ reader.template(key)
44
+ end
45
+
46
+ def config
47
+ @config ||= self.class.config.clone
48
+ end
49
+
50
+ class << self
51
+ attr_accessor :config
52
+ end
53
+
54
+ def self.omitted_namespace
55
+ config && config.omitted_namespace
56
+ end
57
+
58
+ private
59
+
60
+ def collections
61
+ config.collections.map {|collection| send(collection) }
62
+ end
63
+
64
+ def data_attributes
65
+ extract_local_attributes(config.data_attributes).merge(___type: self.class.to_s)
66
+ end
67
+
68
+ def markdown_attributes
69
+ extract_local_attributes(config.markdown_attributes)
70
+ end
71
+
72
+ def extract_local_attributes(keys)
73
+ keys.inject({}) do |hash, key|
74
+ hash[key] = public_send(key)
75
+ hash
76
+ end
77
+ end
78
+
79
+ def writer
80
+ @writer ||= Writer.new(config)
81
+ end
82
+
83
+ def reader
84
+ @reader ||= Reader.new(config)
85
+ end
86
+ end
87
+ end