ki 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.3@ki
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "rack"
4
+ gem "thin"
5
+ gem "mongo"
6
+ gem "bson_ext"
7
+ gem "haml"
8
+ gem "thor"
9
+
10
+ group :development do
11
+ gem "shotgun"
12
+ gem "rspec"
13
+ gem "bundler"
14
+ gem "jeweler"
15
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Cristian Mircea Messel
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,12 @@
1
+ = ki
2
+
3
+ Description goes here.
4
+
5
+ == Contributing to ki
6
+
7
+
8
+ == Copyright
9
+
10
+ Copyright (c) 2012 Cristian Mircea Messel. See LICENSE.txt for
11
+ further details.
12
+
data/Rakefile ADDED
@@ -0,0 +1,34 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "ki"
18
+ gem.homepage = "http://github.com/mess110/ki"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{one-line summary of your gem}
21
+ gem.description = %Q{longer description of your gem}
22
+ gem.email = "mess110@gmail.com"
23
+ gem.authors = ["Cristian Mircea Messel"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rspec/core'
29
+ require 'rspec/core/rake_task'
30
+ RSpec::Core::RakeTask.new(:spec) do |spec|
31
+ spec.pattern = FileList['spec/**/*_spec.rb']
32
+ end
33
+
34
+ task :default => :spec
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
data/bin/ki ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+ require 'cli'
5
+
6
+ Cli.start
@@ -0,0 +1,5 @@
1
+ gem 'ki'
2
+
3
+ group :development do
4
+ gem 'shotgun'
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'ki'
2
+
3
+ class User < Ki::Model
4
+ requires :name
5
+ end
@@ -0,0 +1,2 @@
1
+ require './app'
2
+ run Ki::Ki.new
@@ -0,0 +1,3 @@
1
+ host: 127.0.0.1
2
+ port: 27017
3
+ db_name: example
@@ -0,0 +1,2 @@
1
+ gem 'ki'
2
+ gem 'shotgun'
@@ -0,0 +1,19 @@
1
+ require 'ki'
2
+
3
+ class Phone < Ki::Model
4
+ forbid :delete
5
+ requires :foo, :bar
6
+ end
7
+
8
+ class User < Ki::Model
9
+ requires :name, :password
10
+ respond_to :json
11
+
12
+ def before_create
13
+ @req.params[:password] = 'hashed password'
14
+ end
15
+ end
16
+
17
+ class Post < Ki::Model
18
+ requires :text
19
+ end
@@ -0,0 +1,2 @@
1
+ require './app'
2
+ run Ki::Ki.new
@@ -0,0 +1,3 @@
1
+ host: 127.0.0.1
2
+ port: 27017
3
+ db_name: example
File without changes
File without changes
data/lib/cli.rb ADDED
@@ -0,0 +1,43 @@
1
+ require 'thor'
2
+ require 'thor/group'
3
+
4
+ class AppGenerator < Thor::Group
5
+ include Thor::Actions
6
+
7
+ argument :app_name
8
+
9
+ def self.source_root
10
+ File.join(File.dirname(__FILE__), '..', 'examples', 'base')
11
+ end
12
+
13
+ def dest_root
14
+ File.join(Dir.pwd, app_name)
15
+ end
16
+
17
+ def prepare_dir
18
+ if Dir.exists? dest_root
19
+ unless yes? "#{app_name} already exists. Do you want to overwrite it?"
20
+ say 'aborted'
21
+ exit 1
22
+ end
23
+ else
24
+ Dir.mkdir dest_root
25
+ end
26
+ end
27
+
28
+ def create_app
29
+ copy_file "Gemfile", "#{app_name}/Gemfile"
30
+ copy_file "config.ru", "#{app_name}/config.ru"
31
+ copy_file "config.yml", "#{app_name}/config.yml"
32
+ copy_file "app.rb", "#{app_name}/app.rb"
33
+ end
34
+ end
35
+
36
+ class Cli < Thor
37
+ register AppGenerator, :new, 'new', 'generate a new app'
38
+
39
+ desc 'hello [NAME]', 'says hello'
40
+ def hello(name)
41
+ say "Hello #{name}"
42
+ end
43
+ end
data/lib/controller.rb ADDED
@@ -0,0 +1,15 @@
1
+ module Ki
2
+ class Controller
3
+ def call(env)
4
+ req = Request.new env
5
+ klass = req.klass
6
+ if klass.nil?
7
+ model = Model.new(req)
8
+ else
9
+ model = klass.new(req)
10
+ end
11
+ resp = Response.new(model)
12
+ resp.serve
13
+ end
14
+ end
15
+ end
data/lib/db.rb ADDED
@@ -0,0 +1,49 @@
1
+ require 'mongo'
2
+ require 'singleton'
3
+ require 'json'
4
+
5
+ module Ki
6
+ class Db
7
+ include Singleton
8
+
9
+ attr_accessor :db
10
+
11
+ def all name
12
+ items = []
13
+ @db[name].find.each { |row| items << row }
14
+ items
15
+ end
16
+
17
+ def find name, id
18
+ item = @db[name].find(:_id => BSON::ObjectId(id))
19
+ item.to_a.first
20
+ end
21
+
22
+ def insert name, hash
23
+ @db[name].insert(hash)
24
+ end
25
+
26
+ # document doesn't update if id is in the hash
27
+ def update name, hash
28
+ id = hash['_id']
29
+ hash.delete('_id')
30
+ @db[name].update({:_id => BSON::ObjectId(id)}, hash)
31
+ end
32
+
33
+ def remove name, id
34
+ @db[name].remove(:_id => BSON::ObjectId(id))
35
+ end
36
+
37
+ def clear_model_subclasses
38
+ @db['ki_model_subclasses'].remove
39
+ end
40
+
41
+ def config host, port, db_name
42
+ @con = Mongo::Connection.new(host, port)
43
+ @db = @con.db(db_name)
44
+ rescue Mongo::ConnectionFailure
45
+ puts "Could not connect to MongoDB"
46
+ exit 1
47
+ end
48
+ end
49
+ end
data/lib/ki.rb ADDED
@@ -0,0 +1,41 @@
1
+ require 'rack'
2
+ require 'haml'
3
+
4
+ require 'util'
5
+ require 'db'
6
+ require 'request'
7
+ require 'modules'
8
+ require 'model'
9
+ require 'controller'
10
+ require 'response'
11
+
12
+ Ki::Util.config_db
13
+ Ki::Db.instance.clear_model_subclasses
14
+
15
+ module Ki
16
+ class Ki
17
+ def self.new
18
+ Rack::Builder.new do
19
+ static_path = File.join(Ki.root, 'lib/public/*')
20
+ static_files = Dir.glob(static_path).collect{|c| File.basename(c)}
21
+ static_files.each do |sf|
22
+ map "/public/#{sf}" do
23
+ run Rack::File.new(Util::public_dir(sf))
24
+ end
25
+ end
26
+
27
+ map '/' do
28
+ run Controller.new
29
+ end
30
+ end
31
+ end
32
+
33
+ def self.root
34
+ File.join(File.expand_path(File.join(File.dirname(__FILE__), '..')))
35
+ end
36
+
37
+ def self.app_name
38
+ File.basename(Dir.getwd)
39
+ end
40
+ end
41
+ end
data/lib/model.rb ADDED
@@ -0,0 +1,128 @@
1
+ module Ki
2
+ class Model
3
+ extend Restrictions
4
+ include Callbacks
5
+
6
+ attr_reader :req
7
+
8
+ def initialize req
9
+ @req = req
10
+ @db = Db.instance
11
+ end
12
+
13
+ def forbid_actions
14
+ []
15
+ end
16
+
17
+ def respond_to
18
+ [:json, :html]
19
+ end
20
+
21
+ def required_attributes
22
+ []
23
+ end
24
+
25
+ def format_response code, message, error=false
26
+ if message.class == String
27
+ message = { :message => message }
28
+ end
29
+ unless message.class == Array
30
+ message = [message]
31
+ end
32
+
33
+ # fix this hack
34
+ @req[:code] = code
35
+
36
+ return {
37
+ :code => code,
38
+ :message => message,
39
+ :format => @req.format
40
+ }
41
+ end
42
+
43
+ # TODO fix this method
44
+ def to_response
45
+ if self.class == Model
46
+ return format_response(404, 'did you get lost?')
47
+ end
48
+
49
+ unless respond_to.include? @req.format
50
+ return format_response(403, 'format not allowed')
51
+ end
52
+
53
+ unless route_allowed?
54
+ return format_response(403, 'not allowed')
55
+ end
56
+
57
+ case @req.request_method
58
+ when 'GET'
59
+ if @req.params['_id']
60
+ s = @db.find(@req.base, @req.params['_id'])
61
+ else
62
+ s = @db.all(@req.base)
63
+ end
64
+
65
+ return format_response(200, s)
66
+ when 'POST'
67
+ before_create
68
+ required_attributes.each do |ra|
69
+ unless @req.params.keys.include? ra.to_s
70
+ return format_response(400, "required attribute #{ra} missing")
71
+ end
72
+ end
73
+ id = @db.insert(@req.base, @req.params)
74
+ after_create
75
+ return format_response(200, id)
76
+ when 'PUT'
77
+ if @req.params['_id']
78
+ required_attributes.each do |ra|
79
+ unless @req.params.keys.include? ra.to_s
80
+ return format_response(400, "required attribute #{ra} missing")
81
+ end
82
+ end
83
+
84
+ before_update
85
+ result = @db.update(@req.base, @req.params)
86
+ after_update
87
+ return format_response(200, result)
88
+ else
89
+ return format_response(400, 'missing param _id')
90
+ end
91
+ when 'DELETE'
92
+ if @req.params['_id']
93
+ before_delete
94
+ result = @db.remove(@req.base, @req.params['_id'])
95
+ after_delete
96
+ return format_response(200, result)
97
+ else
98
+ return format_response(400, 'missing param _id')
99
+ end
100
+ else
101
+ return format_response(405, 'method not allowed')
102
+ end
103
+ rescue BSON::InvalidObjectId
104
+ return format_response(400, "invalid object _id")
105
+ end
106
+
107
+ private
108
+
109
+ def route_allowed?
110
+ case @req.request_method
111
+ when 'GET'
112
+ if @req.params['_id']
113
+ !forbid_actions.include? :find
114
+ else
115
+ !forbid_actions.include? :find_all
116
+ end
117
+ when 'POST'
118
+ !forbid_actions.include? :create
119
+ when 'PUT'
120
+ !forbid_actions.include? :update
121
+ when 'DELETE'
122
+ !forbid_actions.include? :delete
123
+ else
124
+ false
125
+ end
126
+ end
127
+ end
128
+ end