ki 0.3.3 → 0.4.1
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 +10 -0
- data/.rspec +1 -1
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +2 -21
- data/Gemfile.lock +60 -100
- data/Guardfile +1 -1
- data/LICENSE.md +21 -0
- data/README.md +63 -0
- data/Rakefile +3 -45
- data/bin/ki +1 -1
- data/ki.gemspec +31 -137
- data/lib/ki.rb +21 -21
- data/lib/ki/api_error.rb +28 -0
- data/lib/ki/base_request.rb +34 -0
- data/lib/ki/helpers.rb +55 -0
- data/lib/ki/ki.rb +40 -0
- data/lib/ki/ki_cli.rb +46 -0
- data/lib/ki/ki_config.rb +20 -0
- data/lib/ki/middleware.rb +155 -0
- data/lib/ki/model.rb +70 -0
- data/lib/{modules → ki/modules}/callbacks.rb +0 -0
- data/lib/ki/modules/format_of.rb +10 -0
- data/lib/{modules → ki/modules}/model_helpers.rb +0 -12
- data/lib/ki/modules/public_file_helper.rb +13 -0
- data/lib/ki/modules/query_interface.rb +36 -0
- data/lib/{modules → ki/modules}/restrictions.rb +0 -30
- data/lib/ki/modules/view_helper.rb +13 -0
- data/lib/ki/orm.rb +65 -0
- data/lib/ki/version.rb +3 -0
- data/spec/examples/base/.ruby-gemset +1 -0
- data/spec/examples/base/.ruby-version +1 -0
- data/spec/examples/base/Gemfile +4 -0
- data/spec/examples/base/app.rb +1 -0
- data/{examples → spec/examples}/base/config.ru +0 -3
- data/spec/examples/base/config.yml +17 -0
- data/spec/examples/base/public/favicon.ico +0 -0
- data/spec/examples/base/public/javascripts/.gitkeep +0 -0
- data/spec/examples/base/public/stylesheets/.gitkeep +0 -0
- data/spec/examples/base/views/index.haml +6 -0
- data/spec/examples/couch-lock/.ruby-gemset +1 -0
- data/spec/examples/couch-lock/.ruby-version +1 -0
- data/spec/examples/couch-lock/Gemfile +4 -0
- data/spec/examples/couch-lock/Gemfile.lock +48 -0
- data/spec/examples/couch-lock/app.rb +42 -0
- data/spec/examples/couch-lock/config.ru +3 -0
- data/spec/examples/couch-lock/config.yml +17 -0
- data/spec/examples/couch-lock/install.sh +3 -0
- data/spec/examples/couch-lock/public/favicon.ico +0 -0
- data/spec/examples/couch-lock/public/javascripts/.gitkeep +0 -0
- data/spec/examples/couch-lock/public/stylesheets/.gitkeep +0 -0
- data/spec/examples/couch-lock/views/index.haml +18 -0
- data/spec/examples/json.northpole.ro/.ruby-gemset +1 -0
- data/spec/examples/json.northpole.ro/.ruby-version +1 -0
- data/spec/examples/json.northpole.ro/Capfile +25 -0
- data/spec/examples/json.northpole.ro/Gemfile +6 -0
- data/spec/examples/json.northpole.ro/Gemfile.lock +68 -0
- data/spec/examples/json.northpole.ro/app.rb +79 -0
- data/spec/examples/json.northpole.ro/client.rb +25 -0
- data/spec/examples/json.northpole.ro/config.ru +3 -0
- data/spec/examples/json.northpole.ro/config.yml +17 -0
- data/spec/examples/json.northpole.ro/config/deploy.rb +59 -0
- data/spec/examples/json.northpole.ro/config/deploy/production.rb +39 -0
- data/spec/examples/json.northpole.ro/foo.rb +10 -0
- data/spec/examples/json.northpole.ro/public/JNorthPole.jar +0 -0
- data/spec/examples/json.northpole.ro/public/favicon.ico +0 -0
- data/spec/examples/json.northpole.ro/public/font/FontAwesome.otf +0 -0
- data/spec/examples/json.northpole.ro/public/font/fontawesome-webfont.eot +0 -0
- data/spec/examples/json.northpole.ro/public/font/fontawesome-webfont.svg +284 -0
- data/spec/examples/json.northpole.ro/public/font/fontawesome-webfont.ttf +0 -0
- data/spec/examples/json.northpole.ro/public/font/fontawesome-webfont.woff +0 -0
- data/spec/examples/json.northpole.ro/public/images/bear.png +0 -0
- data/spec/examples/json.northpole.ro/public/images/bg.png +0 -0
- data/spec/examples/json.northpole.ro/public/images/cloud.png +0 -0
- data/spec/examples/json.northpole.ro/public/images/dotnet.png +0 -0
- data/spec/examples/json.northpole.ro/public/images/dotnet_small.png +0 -0
- data/spec/examples/json.northpole.ro/public/images/footer.png +0 -0
- data/spec/examples/json.northpole.ro/public/images/glyphicons-halflings-white.png +0 -0
- data/spec/examples/json.northpole.ro/public/images/glyphicons-halflings.png +0 -0
- data/spec/examples/json.northpole.ro/public/images/ice.png +0 -0
- data/spec/examples/json.northpole.ro/public/images/java.png +0 -0
- data/spec/examples/json.northpole.ro/public/images/java_small.png +0 -0
- data/spec/examples/json.northpole.ro/public/images/json.png +0 -0
- data/spec/examples/json.northpole.ro/public/images/json_small.png +0 -0
- data/spec/examples/json.northpole.ro/public/images/logo.png +0 -0
- data/spec/examples/json.northpole.ro/public/images/mobile.png +0 -0
- data/spec/examples/json.northpole.ro/public/images/php.png +0 -0
- data/spec/examples/json.northpole.ro/public/images/php_small.png +0 -0
- data/spec/examples/json.northpole.ro/public/images/python.png +0 -0
- data/spec/examples/json.northpole.ro/public/images/python_small.png +0 -0
- data/spec/examples/json.northpole.ro/public/images/ruby.png +0 -0
- data/spec/examples/json.northpole.ro/public/images/ruby_small.png +0 -0
- data/spec/examples/json.northpole.ro/public/images/shell.png +0 -0
- data/spec/examples/json.northpole.ro/public/images/shell_small.png +0 -0
- data/spec/examples/json.northpole.ro/public/javascripts/analytics.js +9 -0
- data/spec/examples/json.northpole.ro/public/javascripts/app.coffee +133 -0
- data/spec/examples/json.northpole.ro/public/javascripts/docs.min.js +16 -0
- data/spec/examples/json.northpole.ro/public/javascripts/jnorthpole.coffee +34 -0
- data/spec/examples/json.northpole.ro/public/javascripts/util.coffee +31 -0
- data/spec/examples/json.northpole.ro/public/stylesheets/app.sass +23 -0
- data/spec/examples/json.northpole.ro/public/stylesheets/application.sass +222 -0
- data/spec/examples/json.northpole.ro/public/stylesheets/cover.css +154 -0
- data/spec/examples/json.northpole.ro/views/curl.haml +19 -0
- data/spec/examples/json.northpole.ro/views/doc.haml +16 -0
- data/spec/examples/json.northpole.ro/views/doc_table.haml +45 -0
- data/spec/examples/json.northpole.ro/views/dotnet.haml +24 -0
- data/spec/examples/json.northpole.ro/views/examples.haml +28 -0
- data/spec/examples/json.northpole.ro/views/faq.haml +32 -0
- data/spec/examples/json.northpole.ro/views/foo.haml +7 -0
- data/spec/examples/json.northpole.ro/views/index.haml +4 -0
- data/spec/examples/json.northpole.ro/views/java.haml +0 -0
- data/spec/examples/json.northpole.ro/views/layout.haml +42 -0
- data/spec/examples/json.northpole.ro/views/php.haml +37 -0
- data/spec/examples/json.northpole.ro/views/playground.haml +38 -0
- data/spec/examples/json.northpole.ro/views/python.haml +17 -0
- data/spec/examples/json.northpole.ro/views/ruby.haml +12 -0
- data/spec/examples/json.northpole.ro/views/signup.haml +2 -0
- data/spec/examples/json.northpole.ro/views/thanks.haml +12 -0
- data/spec/functional_spec.rb +4 -0
- data/spec/lib/ki/base_request_spec.rb +88 -0
- data/spec/lib/ki/helpers_spec.rb +12 -0
- data/spec/lib/ki/ki_config_spec.rb +7 -0
- data/spec/lib/ki/middleware_spec.rb +11 -0
- data/spec/lib/ki/model_spec.rb +100 -0
- data/spec/lib/ki/modules/format_of_spec.rb +15 -0
- data/spec/lib/ki/orm_spec.rb +83 -0
- data/spec/spec_helper.rb +18 -5
- data/spec/util_spec.rb +7 -36
- metadata +269 -193
- data/.document +0 -5
- data/.rvmrc +0 -1
- data/LICENSE.txt +0 -20
- data/README.rdoc +0 -3
- data/VERSION +0 -1
- data/examples/base/Gemfile +0 -3
- data/examples/base/Gemfile.lock +0 -24
- data/examples/base/app.rb +0 -4
- data/examples/base/config.yml +0 -16
- data/gfx/colors.xcf +0 -0
- data/gfx/ki3.eps +0 -0
- data/gfx/logo.png +0 -0
- data/ki_wrap.rb +0 -35
- data/lib/conf.rb +0 -28
- data/lib/db.rb +0 -73
- data/lib/helpers.rb +0 -34
- data/lib/ki_cli.rb +0 -76
- data/lib/mockreq.rb +0 -45
- data/lib/model.rb +0 -110
- data/lib/modules/email.rb +0 -51
- data/lib/modules/query_interface.rb +0 -42
- data/lib/req.rb +0 -57
- data/lib/resp.rb +0 -70
- data/lib/static_file.rb +0 -68
- data/lib/util.rb +0 -114
- data/lib/views/404.haml +0 -1
- data/lib/views/406.haml +0 -1
- data/lib/views/index.haml +0 -7
- data/lib/views/layout.haml +0 -1
- data/spec/conf_spec.rb +0 -6
- data/spec/db_spec.rb +0 -93
- data/spec/integration/integration_spec.rb +0 -114
- data/spec/ki_spec.rb +0 -7
- data/spec/model_spec.rb +0 -91
- data/spec/modules/callbacks_spec.rb +0 -25
- data/spec/modules/email_spec.rb +0 -19
- data/spec/modules/query_interface_spec.rb +0 -93
- data/spec/modules/restrictions_spec.rb +0 -110
- data/spec/performance/performance.sh +0 -1
- data/spec/req_spec.rb +0 -29
data/lib/ki.rb
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'yaml'
|
|
2
|
+
require 'uri'
|
|
2
3
|
|
|
4
|
+
require 'rack'
|
|
5
|
+
require 'rack/parser'
|
|
3
6
|
require 'haml'
|
|
4
7
|
require 'sass'
|
|
5
8
|
require 'coffee-script'
|
|
9
|
+
require 'mongo'
|
|
10
|
+
|
|
6
11
|
|
|
7
|
-
require '
|
|
8
|
-
require 'db'
|
|
9
|
-
require 'model'
|
|
10
|
-
require 'helpers'
|
|
11
|
-
require 'util'
|
|
12
|
-
require 'req'
|
|
13
|
-
require 'resp'
|
|
14
|
-
require 'static_file'
|
|
15
|
-
require 'mockreq'
|
|
12
|
+
require 'ki/api_error'
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
require 'ki/modules/query_interface'
|
|
15
|
+
require 'ki/modules/restrictions'
|
|
16
|
+
require 'ki/modules/callbacks'
|
|
17
|
+
require 'ki/modules/model_helpers'
|
|
18
|
+
require 'ki/modules/view_helper'
|
|
19
|
+
require 'ki/modules/format_of'
|
|
20
|
+
require 'ki/modules/public_file_helper'
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
require 'ki/ki_config'
|
|
23
|
+
require 'ki/helpers'
|
|
24
|
+
require 'ki/orm'
|
|
25
|
+
require 'ki/ki'
|
|
26
|
+
require 'ki/model'
|
|
27
|
+
require 'ki/middleware'
|
|
28
|
+
require 'ki/base_request'
|
data/lib/ki/api_error.rb
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Ki
|
|
2
|
+
class ApiError < StandardError
|
|
3
|
+
attr_reader :status
|
|
4
|
+
|
|
5
|
+
def initialize body, status=400
|
|
6
|
+
super body
|
|
7
|
+
@status = status
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def result
|
|
11
|
+
{ 'error' => to_s }
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class InvalidUrlError < ApiError; end
|
|
16
|
+
class RequiredAttributeMissing < ApiError; end
|
|
17
|
+
class AttributeNotUnique < ApiError; end
|
|
18
|
+
class ForbiddenAction < ApiError
|
|
19
|
+
def initialize
|
|
20
|
+
super 'action forbidden', 400
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
class PartialNotFoundError < ApiError
|
|
24
|
+
def initialize s
|
|
25
|
+
super "partial #{s} not found", 404
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Ki
|
|
2
|
+
class BaseRequest < Rack::Request
|
|
3
|
+
include FormatOf
|
|
4
|
+
|
|
5
|
+
def root?
|
|
6
|
+
path == '/'
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def json?
|
|
10
|
+
content_type == 'application/json' || format_of(path) == 'json'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def to_ki_model_class
|
|
14
|
+
self.path.to_s.gsub('/','').gsub(format_of(path), '').gsub('.', '').to_class
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def to_action
|
|
18
|
+
case request_method
|
|
19
|
+
when 'GET'
|
|
20
|
+
:find
|
|
21
|
+
when 'POST'
|
|
22
|
+
:create
|
|
23
|
+
when 'PUT'
|
|
24
|
+
:update
|
|
25
|
+
when 'DELETE'
|
|
26
|
+
:delete
|
|
27
|
+
when 'SEARCH'
|
|
28
|
+
:find
|
|
29
|
+
else
|
|
30
|
+
raise 'unkown action'
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
data/lib/ki/helpers.rb
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
class String
|
|
2
|
+
def to_class
|
|
3
|
+
chain = self.split "::"
|
|
4
|
+
klass = Kernel
|
|
5
|
+
chain.each do |klass_string|
|
|
6
|
+
klass = klass.const_get klass_string.capitalize
|
|
7
|
+
end
|
|
8
|
+
klass.is_a?(Class) ? klass : nil
|
|
9
|
+
rescue NameError
|
|
10
|
+
nil
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class Array
|
|
15
|
+
def stringify_ids
|
|
16
|
+
self.collect do |e|
|
|
17
|
+
if e['_id']
|
|
18
|
+
e['id'] = e['_id'].to_s
|
|
19
|
+
e.delete('_id')
|
|
20
|
+
end
|
|
21
|
+
if e[:_id]
|
|
22
|
+
e['id'] = e[:_id].to_s
|
|
23
|
+
e.delete(:_id)
|
|
24
|
+
end
|
|
25
|
+
e
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
module Ki
|
|
31
|
+
module Helpers
|
|
32
|
+
include ViewHelper
|
|
33
|
+
|
|
34
|
+
def css url
|
|
35
|
+
render_haml "%link{:href => '#{url}', :rel => 'stylesheet'}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def js url
|
|
39
|
+
render_haml "%script{:src => '#{url}'}"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def render_haml s
|
|
43
|
+
Haml::Engine.new(s).render
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def partial s
|
|
47
|
+
path = view_path(s)
|
|
48
|
+
if File.file?(path)
|
|
49
|
+
render_haml(File.read(path))
|
|
50
|
+
else
|
|
51
|
+
raise PartialNotFoundError.new path
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
data/lib/ki/ki.rb
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Ki
|
|
2
|
+
class KiApp
|
|
3
|
+
# should never reach this
|
|
4
|
+
# middleware should catch all the requests
|
|
5
|
+
def call env
|
|
6
|
+
s = 'misplaced in space'
|
|
7
|
+
Rack::Response.new(s).finish
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class Ki
|
|
12
|
+
PUBLIC_PATH = 'public'
|
|
13
|
+
VIEWS_PATH = 'views'
|
|
14
|
+
|
|
15
|
+
def initialize
|
|
16
|
+
KiConfig.instance.read environment
|
|
17
|
+
Orm::Db.instance.establish_connection
|
|
18
|
+
|
|
19
|
+
@app = Rack::Builder.new do
|
|
20
|
+
use Middleware::InitMiddleware
|
|
21
|
+
# TODO what happens with invalid json?
|
|
22
|
+
use Rack::Parser, :content_types => { 'application/json' => Proc.new { |body| ::MultiJson.decode body } }
|
|
23
|
+
use Middleware::ApiHandler
|
|
24
|
+
use Middleware::CoffeeCompiler
|
|
25
|
+
use Middleware::SassCompiler
|
|
26
|
+
use Middleware::HamlCompiler
|
|
27
|
+
use Middleware::PublicFileServer
|
|
28
|
+
run KiApp.new
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def environment
|
|
33
|
+
ENV['RACK_ENV']
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def call env
|
|
37
|
+
@app.call env
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
data/lib/ki/ki_cli.rb
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'thor'
|
|
2
|
+
|
|
3
|
+
class KiGenerator < Thor::Group
|
|
4
|
+
include Thor::Actions
|
|
5
|
+
|
|
6
|
+
def self.source_root
|
|
7
|
+
File.join(File.dirname(__FILE__), '..', '..')
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class AppGenerator < KiGenerator
|
|
12
|
+
|
|
13
|
+
argument :app_name
|
|
14
|
+
|
|
15
|
+
def prepare_dir
|
|
16
|
+
unless app_name =~ /^[a-zA-Z0-9-]*$/
|
|
17
|
+
say "App name must contain only alphanumeric characters and -"
|
|
18
|
+
exit 1
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
if Dir.exists? app_name
|
|
22
|
+
say "#{app_name} already exists"
|
|
23
|
+
exit 2
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
Dir.mkdir app_name
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def create_app
|
|
30
|
+
directory("spec/examples/base", app_name)
|
|
31
|
+
|
|
32
|
+
# Set database names
|
|
33
|
+
config_file = File.read("#{app_name}/config.yml")
|
|
34
|
+
config_file.gsub!("name: np_development", "name: #{app_name}_development")
|
|
35
|
+
config_file.gsub!("name: np_test", "name: #{app_name}_test")
|
|
36
|
+
config_file.gsub!("name: np", "name: #{app_name}")
|
|
37
|
+
File.open("#{app_name}/config.yml", "w") {|file| file.puts config_file}
|
|
38
|
+
|
|
39
|
+
# Set rvm gemset name
|
|
40
|
+
`echo #{app_name} > #{app_name}/.ruby-gemset`
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class KiCli < Thor
|
|
45
|
+
register AppGenerator, :new, 'new [APP_NAME]', 'generate a new app'
|
|
46
|
+
end
|
data/lib/ki/ki_config.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'singleton'
|
|
2
|
+
|
|
3
|
+
module Ki
|
|
4
|
+
class KiConfig
|
|
5
|
+
include Singleton
|
|
6
|
+
|
|
7
|
+
CONFIG_FILE_PATH = 'config.yml'
|
|
8
|
+
|
|
9
|
+
attr_reader :config, :environment
|
|
10
|
+
|
|
11
|
+
def read environment
|
|
12
|
+
@environment = environment
|
|
13
|
+
@config = YAML.load_file(CONFIG_FILE_PATH)[environment]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def database
|
|
17
|
+
@config['database']
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
module Ki
|
|
2
|
+
module Middleware
|
|
3
|
+
module BaseMiddleware
|
|
4
|
+
include FormatOf
|
|
5
|
+
include ViewHelper
|
|
6
|
+
include PublicFileHelper
|
|
7
|
+
|
|
8
|
+
def initialize app
|
|
9
|
+
@app = app
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class PublicFileServer
|
|
14
|
+
include BaseMiddleware
|
|
15
|
+
|
|
16
|
+
def call env
|
|
17
|
+
req = BaseRequest.new env
|
|
18
|
+
if public_file_exists? req
|
|
19
|
+
Rack::File.new(Ki::PUBLIC_PATH).call env
|
|
20
|
+
else
|
|
21
|
+
@app.call env
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class InitMiddleware
|
|
27
|
+
include BaseMiddleware
|
|
28
|
+
|
|
29
|
+
def call env
|
|
30
|
+
req = BaseRequest.new env
|
|
31
|
+
if req.root?
|
|
32
|
+
resp = Rack::Response.new
|
|
33
|
+
resp.redirect('/index')
|
|
34
|
+
resp.finish
|
|
35
|
+
else
|
|
36
|
+
env['CONTENT_TYPE'] = 'application/json' if format_of(req) == 'json'
|
|
37
|
+
@app.call env
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
class HamlCompiler
|
|
43
|
+
include BaseMiddleware
|
|
44
|
+
|
|
45
|
+
def call env
|
|
46
|
+
req = BaseRequest.new env
|
|
47
|
+
if view_exists?(req)
|
|
48
|
+
render_haml view_path(req)
|
|
49
|
+
else
|
|
50
|
+
@app.call env
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def render_haml file_path
|
|
55
|
+
file_contents = File.read(file_path)
|
|
56
|
+
|
|
57
|
+
if view_exists? 'layout'
|
|
58
|
+
layout_contents = File.read(view_path('layout'))
|
|
59
|
+
else
|
|
60
|
+
layout_contents = "= yield"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
html = haml(layout_contents).render do
|
|
64
|
+
haml(file_contents).render
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
Rack::Response.new(html).finish
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def haml s
|
|
71
|
+
Haml::Engine.new("- extend Ki::Helpers\n" + s)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
class CoffeeCompiler
|
|
76
|
+
include BaseMiddleware
|
|
77
|
+
|
|
78
|
+
def call env
|
|
79
|
+
req = BaseRequest.new env
|
|
80
|
+
coffee_path = req.path.to_s[0...-3] + '.coffee'
|
|
81
|
+
if !public_file_exists?(req) && format_of(req) == 'js' && public_file_exists?(coffee_path)
|
|
82
|
+
js = CoffeeScript.compile(File.read(public_file_path(coffee_path)))
|
|
83
|
+
Rack::Response.new(js).finish
|
|
84
|
+
else
|
|
85
|
+
@app.call env
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
class SassCompiler
|
|
91
|
+
include BaseMiddleware
|
|
92
|
+
|
|
93
|
+
def call env
|
|
94
|
+
req = BaseRequest.new env
|
|
95
|
+
sass_path = req.path.to_s[0...-4] + '.sass'
|
|
96
|
+
# if req ends with css and it does not exist, if a sass file exists instead
|
|
97
|
+
if !public_file_exists?(req) && format_of(req) == 'css' && public_file_exists?(sass_path)
|
|
98
|
+
eng = Sass::Engine.new(File.read(public_file_path(sass_path)), :syntax => :sass)
|
|
99
|
+
Rack::Response.new(eng.render).finish
|
|
100
|
+
else
|
|
101
|
+
@app.call env
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Handles all API calls
|
|
107
|
+
#
|
|
108
|
+
# Any json request is considered an api call. A request is considered as json
|
|
109
|
+
# if the format is .json or Content-Type header is set to 'application/json'
|
|
110
|
+
#
|
|
111
|
+
# If the query param 'redirect_to' is given, the response will not contain the
|
|
112
|
+
# json output from the url, instead it will redirect to the url given
|
|
113
|
+
class ApiHandler
|
|
114
|
+
include BaseMiddleware
|
|
115
|
+
|
|
116
|
+
def call env
|
|
117
|
+
req = BaseRequest.new env
|
|
118
|
+
if req.json?
|
|
119
|
+
begin
|
|
120
|
+
klass = req.to_ki_model_class
|
|
121
|
+
if Model.descendants.include? klass
|
|
122
|
+
# TODO do not have redirect_to param
|
|
123
|
+
model = klass.new(req.to_action, req.params)
|
|
124
|
+
# TODO document this
|
|
125
|
+
if req.params['redirect_to'].nil?
|
|
126
|
+
render model
|
|
127
|
+
else
|
|
128
|
+
# TODO check for injection
|
|
129
|
+
redirect_to req.params['redirect_to']
|
|
130
|
+
end
|
|
131
|
+
else
|
|
132
|
+
raise InvalidUrlError.new("invalid url '#{req.path}'", 404)
|
|
133
|
+
end
|
|
134
|
+
rescue ApiError => e
|
|
135
|
+
render e
|
|
136
|
+
end
|
|
137
|
+
else
|
|
138
|
+
@app.call env
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def redirect_to s
|
|
143
|
+
resp = Rack::Response.new
|
|
144
|
+
resp.redirect(s)
|
|
145
|
+
resp.finish
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def render r
|
|
149
|
+
resp = Rack::Response.new(r.result.to_json, r.status)
|
|
150
|
+
resp['Content-Type'] = 'application/json'
|
|
151
|
+
resp.finish
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
data/lib/ki/model.rb
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module Ki
|
|
2
|
+
class Model
|
|
3
|
+
extend QueryInterface
|
|
4
|
+
extend Restrictions
|
|
5
|
+
include Callbacks
|
|
6
|
+
include ModelHelpers
|
|
7
|
+
|
|
8
|
+
attr_accessor :action, :result, :params, :status
|
|
9
|
+
|
|
10
|
+
def initialize action, params
|
|
11
|
+
@action = action
|
|
12
|
+
@params = params
|
|
13
|
+
@status = 200
|
|
14
|
+
|
|
15
|
+
raise ForbiddenAction.new if forbidden_actions.include? @action
|
|
16
|
+
ccall
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def find
|
|
20
|
+
@result = self.class.find @params
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def create
|
|
24
|
+
check_for_required_attributes
|
|
25
|
+
check_for_unique_attributes
|
|
26
|
+
@result = self.class.create @params
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def update
|
|
30
|
+
check_for_required_attributes
|
|
31
|
+
check_for_unique_attributes
|
|
32
|
+
@result = self.class.update @params
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def delete
|
|
36
|
+
@result = self.class.delete @params
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def check_for_required_attributes
|
|
42
|
+
required_attributes.each do |ra|
|
|
43
|
+
if !@params.keys.include?(ra.to_s)
|
|
44
|
+
raise RequiredAttributeMissing.new("#{ra.to_s} missing")
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def check_for_unique_attributes
|
|
50
|
+
unique_attributes.each do |ua|
|
|
51
|
+
u = self.class.find({ua.to_s => @params[ua.to_s]})
|
|
52
|
+
unless u.empty?
|
|
53
|
+
raise AttributeNotUnique.new("#{ua.to_s} not unique")
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def ccall
|
|
59
|
+
before_all
|
|
60
|
+
send "before_#{@action.to_s}".to_sym
|
|
61
|
+
send @action.to_sym
|
|
62
|
+
send "after_#{@action.to_s}".to_sym
|
|
63
|
+
after_all
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def self.descendants
|
|
67
|
+
ObjectSpace.each_object(Class).select { |klass| klass < self }
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|