ki 0.0.2 → 0.1.0
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.
- data/.rvmrc +1 -1
- data/Gemfile +6 -3
- data/Gemfile.lock +81 -0
- data/Guardfile +9 -0
- data/LICENSE.txt +1 -1
- data/README.rdoc +8 -1
- data/Rakefile +17 -3
- data/VERSION +1 -1
- data/bin/ki +3 -2
- data/examples/base/Gemfile +1 -7
- data/examples/base/Gemfile.lock +24 -0
- data/examples/base/app.rb +1 -2
- data/examples/base/config.ru +4 -0
- data/examples/{example → northpole}/Gemfile +0 -1
- data/examples/northpole/Gemfile.lock +33 -0
- data/examples/northpole/app.rb +19 -0
- data/examples/northpole/config.ru +6 -0
- data/examples/northpole/config.yml +3 -0
- data/examples/northpole/views/index.haml +1 -0
- data/examples/northpole/views/website.haml +1 -0
- data/ki.gemspec +125 -0
- data/lib/db.rb +43 -13
- data/lib/extensions/mail.rb +41 -0
- data/lib/helpers.rb +16 -0
- data/lib/ki.rb +8 -27
- data/lib/ki_cli.rb +63 -0
- data/lib/model.rb +59 -92
- data/lib/modules/callbacks.rb +27 -0
- data/lib/modules/query_interface.rb +29 -0
- data/lib/modules/restrictions.rb +62 -0
- data/lib/req.rb +30 -0
- data/lib/resp.rb +50 -0
- data/lib/static_file.rb +14 -0
- data/lib/util.rb +21 -30
- data/lib/views/404.haml +7 -0
- data/lib/views/406.haml +7 -0
- data/lib/views/index.haml +5 -17
- data/logo.png +0 -0
- data/spec/db_spec.rb +71 -0
- data/spec/ki_spec.rb +2 -2
- data/spec/model_spec.rb +82 -0
- data/spec/modules/callbacks_spec.rb +14 -0
- data/spec/modules/query_interface_spec.rb +63 -0
- data/spec/modules/restrictions_spec.rb +64 -0
- data/spec/req_spec.rb +4 -0
- data/spec/spec_helper.rb +30 -1
- data/spec/util_spec.rb +32 -16
- metadata +89 -36
- data/examples/base/config.yml +0 -3
- data/examples/example/app.rb +0 -15
- data/examples/example/config.ru +0 -2
- data/examples/example/config.yml +0 -3
- data/examples/example/public/custom.css +0 -0
- data/examples/example/public/custom.js +0 -0
- data/lib/cli.rb +0 -51
- data/lib/controller.rb +0 -15
- data/lib/modules.rb +0 -54
- data/lib/public/bootstrap.css +0 -6004
- data/lib/public/bootstrap.js +0 -2036
- data/lib/public/custom.css +0 -0
- data/lib/public/custom.js +0 -0
- data/lib/public/glyphicons-halflings-white.png +0 -0
- data/lib/public/glyphicons-halflings.png +0 -0
- data/lib/public/jquery-1.8.2.min.js +0 -2
- data/lib/public/ki.css +0 -56
- data/lib/request.rb +0 -14
- data/lib/response.rb +0 -51
- data/lib/views/container.haml +0 -6
- data/lib/views/footer.haml +0 -2
- data/lib/views/form.haml +0 -10
- data/lib/views/models.haml +0 -14
- data/lib/views/navbar.haml +0 -11
data/lib/db.rb
CHANGED
@@ -6,44 +6,74 @@ module Ki
|
|
6
6
|
class Db
|
7
7
|
include Singleton
|
8
8
|
|
9
|
-
|
9
|
+
attr_reader :db
|
10
10
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
def collection_names
|
12
|
+
@db.collection_names.delete_if{|name| name =~ /^system/}
|
13
|
+
end
|
14
|
+
|
15
|
+
def remove_collections
|
16
|
+
collection_names.each{|c| @db[c].drop}
|
17
|
+
end
|
18
|
+
|
19
|
+
def find_all name
|
20
|
+
@db[name].find.collect{ |row| row }
|
15
21
|
end
|
16
22
|
|
17
23
|
def find name, id
|
18
|
-
|
19
|
-
|
24
|
+
@db[name].find( { '_id' => BSON::ObjectId(id) }).first
|
25
|
+
end
|
26
|
+
|
27
|
+
def find_by name, hash
|
28
|
+
@db[name].find(hash).to_a
|
20
29
|
end
|
21
30
|
|
22
|
-
def
|
23
|
-
@db[name].insert(hash)
|
31
|
+
def create name, hash
|
32
|
+
@db[name].insert(hash).to_s
|
24
33
|
end
|
25
34
|
|
26
|
-
# document doesn't update if
|
35
|
+
# document doesn't update if :_id is in the hash
|
36
|
+
# all prev object data is deleted
|
27
37
|
def update name, hash
|
28
38
|
id = hash['_id']
|
29
39
|
hash.delete('_id')
|
30
40
|
@db[name].update({:_id => BSON::ObjectId(id)}, hash)
|
41
|
+
id
|
31
42
|
end
|
32
43
|
|
33
|
-
def
|
44
|
+
def delete name, id
|
34
45
|
@db[name].remove(:_id => BSON::ObjectId(id))
|
35
46
|
end
|
36
47
|
|
37
|
-
def
|
38
|
-
|
48
|
+
def config_db
|
49
|
+
yaml = read_yaml
|
50
|
+
config yaml['host'], yaml['port'], yaml['db_name']
|
39
51
|
end
|
40
52
|
|
41
53
|
def config host, port, db_name
|
54
|
+
# puts "Using #{db_name} at #{host}:#{port}"
|
42
55
|
@con = Mongo::Connection.new(host, port)
|
43
56
|
@db = @con.db(db_name)
|
44
57
|
rescue Mongo::ConnectionFailure
|
45
58
|
puts "Could not connect to MongoDB"
|
46
59
|
exit 1
|
47
60
|
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def read_yaml
|
65
|
+
config_path = File.join(Dir.pwd, 'config.yml')
|
66
|
+
yaml = {}
|
67
|
+
if File.exists? config_path
|
68
|
+
YAML.load_file(config_path)
|
69
|
+
else
|
70
|
+
{
|
71
|
+
'host' => '127.0.0.1',
|
72
|
+
'port' => 27017,
|
73
|
+
'db_name' => Util.app_name
|
74
|
+
}
|
75
|
+
end
|
76
|
+
end
|
48
77
|
end
|
49
78
|
end
|
79
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'net/smtp'
|
2
|
+
|
3
|
+
module Ki
|
4
|
+
# Extension module which helps with sending emails.
|
5
|
+
# Include it in a Ki::Model to load its send_mail method
|
6
|
+
#
|
7
|
+
# === Example
|
8
|
+
# class Article < Ki::Model
|
9
|
+
# include Ki::Mail
|
10
|
+
# end
|
11
|
+
module Mail
|
12
|
+
def send_mail *params
|
13
|
+
params = params[0] if params.class == Array
|
14
|
+
|
15
|
+
if params.length != 4
|
16
|
+
raise 'params missing'
|
17
|
+
end
|
18
|
+
|
19
|
+
params.each do |elem|
|
20
|
+
if !self.class.required_attributes.include? elem
|
21
|
+
raise "invalid attribute #{elem.to_s}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
from = @req[params[0].to_s]
|
26
|
+
to = @req[params[1].to_s]
|
27
|
+
subject = @req[params[2].to_s]
|
28
|
+
body = @req[params[3].to_s]
|
29
|
+
|
30
|
+
really_send "#{subject}\n\n#{body}", from, to
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def really_send message, from, to
|
36
|
+
Net::SMTP.start('localhost') do |smtp|
|
37
|
+
smtp.send_message message, from, to
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/helpers.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module Ki
|
2
|
+
module Helpers
|
3
|
+
def haml contents
|
4
|
+
Haml::Engine.new(contents)
|
5
|
+
end
|
6
|
+
|
7
|
+
def partial s, hash={}
|
8
|
+
path = Util.root_view_path s
|
9
|
+
unless File.exists? path
|
10
|
+
path = File.join(Util.src_path, 'views', s) + '.haml'
|
11
|
+
end
|
12
|
+
contents = File.read(path)
|
13
|
+
haml(contents).render(Object.new(), hash)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/ki.rb
CHANGED
@@ -1,39 +1,20 @@
|
|
1
1
|
require 'rack'
|
2
2
|
require 'haml'
|
3
3
|
|
4
|
-
require 'util'
|
5
4
|
require 'db'
|
6
|
-
require 'request'
|
7
|
-
require 'modules'
|
8
5
|
require 'model'
|
9
|
-
require '
|
10
|
-
require '
|
6
|
+
require 'helpers'
|
7
|
+
require 'util'
|
8
|
+
require 'req'
|
9
|
+
require 'resp'
|
10
|
+
require 'static_file'
|
11
11
|
|
12
|
-
Ki::
|
13
|
-
Ki::Db.instance.clear_model_subclasses
|
12
|
+
Ki::Db.instance.config_db
|
14
13
|
|
15
14
|
module Ki
|
16
15
|
class Ki
|
17
|
-
def
|
18
|
-
|
19
|
-
Util.static_files.each do |sf|
|
20
|
-
map "/public/#{File.basename(sf)}" do
|
21
|
-
run Rack::File.new(sf)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
map '/' do
|
26
|
-
run Controller.new
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def self.root
|
32
|
-
File.join(File.expand_path(File.join(File.dirname(__FILE__), '..')))
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.app_name
|
36
|
-
File.basename(Dir.getwd)
|
16
|
+
def call env
|
17
|
+
Req.new(env).serve
|
37
18
|
end
|
38
19
|
end
|
39
20
|
end
|
data/lib/ki_cli.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
require 'util'
|
4
|
+
|
5
|
+
class KiGenerator < Thor::Group
|
6
|
+
include Thor::Actions
|
7
|
+
|
8
|
+
def self.source_root
|
9
|
+
File.join(File.dirname(__FILE__), '..', 'examples', 'base')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class ConfigGenerator < KiGenerator
|
14
|
+
def generate
|
15
|
+
create_file 'config.yml' do
|
16
|
+
"host: 127.0.0.1\nport: 27017\ndb_name: #{Ki::Util.app_name}\n"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class AppGenerator < KiGenerator
|
22
|
+
|
23
|
+
argument :app_name
|
24
|
+
|
25
|
+
def prepare_dir
|
26
|
+
dest_root = File.join(Dir.pwd, app_name)
|
27
|
+
|
28
|
+
if Dir.exists? dest_root
|
29
|
+
unless yes? "#{app_name} already exists. Do you want to overwrite it?"
|
30
|
+
say 'aborted'
|
31
|
+
exit 1
|
32
|
+
end
|
33
|
+
else
|
34
|
+
Dir.mkdir dest_root
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_app
|
39
|
+
dest_root = File.join(Dir.pwd, app_name)
|
40
|
+
|
41
|
+
['Gemfile', 'config.ru', 'app.rb'].each do |f|
|
42
|
+
copy_file f, File.join(dest_root, f)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class KiCli < Thor
|
48
|
+
register AppGenerator, :new, 'new [APP_NAME]', 'generate a new app'
|
49
|
+
register ConfigGenerator, :config, 'config', 'generate a new config.yml'
|
50
|
+
|
51
|
+
desc 'server', 'starts the app'
|
52
|
+
# method_option :reload, :type => :boolean, :aliases => '-r', :desc => 'Recommended for development'
|
53
|
+
method_option :port, :type => :numeric, :aliases => '-p', :desc => 'port'
|
54
|
+
def server
|
55
|
+
port = options[:port] ? options[:port] : 3000
|
56
|
+
# if options[:reload]
|
57
|
+
# say 'Starting Ki Reloaded', :yellow
|
58
|
+
#else
|
59
|
+
say 'Starting Ki', :green
|
60
|
+
#end
|
61
|
+
system "bundle exec thin start -p #{port}"
|
62
|
+
end
|
63
|
+
end
|
data/lib/model.rb
CHANGED
@@ -1,128 +1,95 @@
|
|
1
|
+
require 'modules/callbacks'
|
2
|
+
require 'modules/restrictions'
|
3
|
+
require 'modules/query_interface'
|
4
|
+
|
5
|
+
require 'extensions/mail'
|
6
|
+
|
1
7
|
module Ki
|
2
8
|
class Model
|
3
9
|
extend Restrictions
|
10
|
+
extend QueryInterface
|
11
|
+
include InitRestrictions
|
4
12
|
include Callbacks
|
5
13
|
|
14
|
+
attr_accessor :hash
|
6
15
|
attr_reader :req
|
7
16
|
|
8
17
|
def initialize req
|
9
|
-
@
|
18
|
+
@hash = {}
|
10
19
|
@db = Db.instance
|
11
|
-
|
20
|
+
@req = req
|
12
21
|
|
13
|
-
|
14
|
-
|
22
|
+
action = to_action(req)
|
23
|
+
raise 'action forbidden' if forbidden_actions.include? action
|
24
|
+
ccall action
|
15
25
|
end
|
16
26
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
27
|
+
def find
|
28
|
+
raise 'params missing' unless @req.params
|
29
|
+
raise 'param _id missing' unless @req.params['_id']
|
20
30
|
|
21
|
-
|
22
|
-
|
31
|
+
@hash = @db.find(class_name, @req.params['_id'])
|
32
|
+
raise "#{class_name} not found" if @hash.nil?
|
23
33
|
end
|
24
34
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
unless message.class == Array
|
30
|
-
message = [message]
|
31
|
-
end
|
35
|
+
def create
|
36
|
+
check_for_required_attributes
|
37
|
+
@hash['_id'] = @db.create(class_name, @req.params)
|
38
|
+
end
|
32
39
|
|
33
|
-
|
34
|
-
@req
|
40
|
+
def update
|
41
|
+
raise 'params missing' unless @req.params
|
42
|
+
raise 'param _id missing' unless @req.params['_id']
|
35
43
|
|
36
|
-
|
37
|
-
|
38
|
-
:message => message,
|
39
|
-
:format => @req.format
|
40
|
-
}
|
44
|
+
check_for_required_attributes
|
45
|
+
@hash['_id'] = @db.update(class_name, @req.params)
|
41
46
|
end
|
42
47
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
return format_response(404, 'did you get lost?')
|
47
|
-
end
|
48
|
+
def delete
|
49
|
+
raise 'params missing' unless @req.params
|
50
|
+
raise 'param _id missing' unless @req.params['_id']
|
48
51
|
|
49
|
-
|
50
|
-
|
51
|
-
end
|
52
|
+
@hash = @db.delete(class_name, @req.params['_id'])
|
53
|
+
end
|
52
54
|
|
53
|
-
|
54
|
-
|
55
|
-
|
55
|
+
def to_json
|
56
|
+
@hash.to_json
|
57
|
+
end
|
56
58
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
s = @db.find(@req.base, @req.params['_id'])
|
61
|
-
else
|
62
|
-
s = @db.all(@req.base)
|
63
|
-
end
|
59
|
+
def class_name
|
60
|
+
self.class.to_s.downcase
|
61
|
+
end
|
64
62
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
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')
|
63
|
+
private
|
64
|
+
|
65
|
+
def check_for_required_attributes
|
66
|
+
required_attributes.each do |ra|
|
67
|
+
unless @req.params.keys.include? ra.to_s
|
68
|
+
raise "#{ra.to_s} missing"
|
99
69
|
end
|
100
|
-
else
|
101
|
-
return format_response(405, 'method not allowed')
|
102
70
|
end
|
103
|
-
rescue BSON::InvalidObjectId
|
104
|
-
return format_response(400, "invalid object _id")
|
105
71
|
end
|
106
72
|
|
107
|
-
|
108
|
-
|
109
|
-
def route_allowed?
|
110
|
-
case @req.request_method
|
73
|
+
def to_action req
|
74
|
+
case req.request_method
|
111
75
|
when 'GET'
|
112
|
-
|
113
|
-
!forbid_actions.include? :find
|
114
|
-
else
|
115
|
-
!forbid_actions.include? :find_all
|
116
|
-
end
|
76
|
+
:find
|
117
77
|
when 'POST'
|
118
|
-
|
78
|
+
:create
|
119
79
|
when 'PUT'
|
120
|
-
|
80
|
+
:update
|
121
81
|
when 'DELETE'
|
122
|
-
|
82
|
+
:delete
|
123
83
|
else
|
124
|
-
|
84
|
+
raise 'unkown action'
|
125
85
|
end
|
126
86
|
end
|
87
|
+
|
88
|
+
# calls method m + before and after methods
|
89
|
+
def ccall m
|
90
|
+
send "before_#{m.to_s}".to_sym
|
91
|
+
send m.to_sym
|
92
|
+
send "after_#{m.to_s}".to_sym
|
93
|
+
end
|
127
94
|
end
|
128
95
|
end
|