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.
Files changed (72) hide show
  1. data/.rvmrc +1 -1
  2. data/Gemfile +6 -3
  3. data/Gemfile.lock +81 -0
  4. data/Guardfile +9 -0
  5. data/LICENSE.txt +1 -1
  6. data/README.rdoc +8 -1
  7. data/Rakefile +17 -3
  8. data/VERSION +1 -1
  9. data/bin/ki +3 -2
  10. data/examples/base/Gemfile +1 -7
  11. data/examples/base/Gemfile.lock +24 -0
  12. data/examples/base/app.rb +1 -2
  13. data/examples/base/config.ru +4 -0
  14. data/examples/{example → northpole}/Gemfile +0 -1
  15. data/examples/northpole/Gemfile.lock +33 -0
  16. data/examples/northpole/app.rb +19 -0
  17. data/examples/northpole/config.ru +6 -0
  18. data/examples/northpole/config.yml +3 -0
  19. data/examples/northpole/views/index.haml +1 -0
  20. data/examples/northpole/views/website.haml +1 -0
  21. data/ki.gemspec +125 -0
  22. data/lib/db.rb +43 -13
  23. data/lib/extensions/mail.rb +41 -0
  24. data/lib/helpers.rb +16 -0
  25. data/lib/ki.rb +8 -27
  26. data/lib/ki_cli.rb +63 -0
  27. data/lib/model.rb +59 -92
  28. data/lib/modules/callbacks.rb +27 -0
  29. data/lib/modules/query_interface.rb +29 -0
  30. data/lib/modules/restrictions.rb +62 -0
  31. data/lib/req.rb +30 -0
  32. data/lib/resp.rb +50 -0
  33. data/lib/static_file.rb +14 -0
  34. data/lib/util.rb +21 -30
  35. data/lib/views/404.haml +7 -0
  36. data/lib/views/406.haml +7 -0
  37. data/lib/views/index.haml +5 -17
  38. data/logo.png +0 -0
  39. data/spec/db_spec.rb +71 -0
  40. data/spec/ki_spec.rb +2 -2
  41. data/spec/model_spec.rb +82 -0
  42. data/spec/modules/callbacks_spec.rb +14 -0
  43. data/spec/modules/query_interface_spec.rb +63 -0
  44. data/spec/modules/restrictions_spec.rb +64 -0
  45. data/spec/req_spec.rb +4 -0
  46. data/spec/spec_helper.rb +30 -1
  47. data/spec/util_spec.rb +32 -16
  48. metadata +89 -36
  49. data/examples/base/config.yml +0 -3
  50. data/examples/example/app.rb +0 -15
  51. data/examples/example/config.ru +0 -2
  52. data/examples/example/config.yml +0 -3
  53. data/examples/example/public/custom.css +0 -0
  54. data/examples/example/public/custom.js +0 -0
  55. data/lib/cli.rb +0 -51
  56. data/lib/controller.rb +0 -15
  57. data/lib/modules.rb +0 -54
  58. data/lib/public/bootstrap.css +0 -6004
  59. data/lib/public/bootstrap.js +0 -2036
  60. data/lib/public/custom.css +0 -0
  61. data/lib/public/custom.js +0 -0
  62. data/lib/public/glyphicons-halflings-white.png +0 -0
  63. data/lib/public/glyphicons-halflings.png +0 -0
  64. data/lib/public/jquery-1.8.2.min.js +0 -2
  65. data/lib/public/ki.css +0 -56
  66. data/lib/request.rb +0 -14
  67. data/lib/response.rb +0 -51
  68. data/lib/views/container.haml +0 -6
  69. data/lib/views/footer.haml +0 -2
  70. data/lib/views/form.haml +0 -10
  71. data/lib/views/models.haml +0 -14
  72. 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
- attr_accessor :db
9
+ attr_reader :db
10
10
 
11
- def all name
12
- items = []
13
- @db[name].find.each { |row| items << row }
14
- items
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
- item = @db[name].find(:_id => BSON::ObjectId(id))
19
- item.to_a.first
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 insert name, hash
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 id is in the hash
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 remove name, id
44
+ def delete name, id
34
45
  @db[name].remove(:_id => BSON::ObjectId(id))
35
46
  end
36
47
 
37
- def clear_model_subclasses
38
- @db['ki_model_subclasses'].remove
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 'controller'
10
- require 'response'
6
+ require 'helpers'
7
+ require 'util'
8
+ require 'req'
9
+ require 'resp'
10
+ require 'static_file'
11
11
 
12
- Ki::Util.config_db
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 self.new
18
- Rack::Builder.new do
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
- @req = req
18
+ @hash = {}
10
19
  @db = Db.instance
11
- end
20
+ @req = req
12
21
 
13
- def forbid_actions
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 respond_to
18
- [:json, :html]
19
- end
27
+ def find
28
+ raise 'params missing' unless @req.params
29
+ raise 'param _id missing' unless @req.params['_id']
20
30
 
21
- def required_attributes
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 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
35
+ def create
36
+ check_for_required_attributes
37
+ @hash['_id'] = @db.create(class_name, @req.params)
38
+ end
32
39
 
33
- # fix this hack
34
- @req[:code] = code
40
+ def update
41
+ raise 'params missing' unless @req.params
42
+ raise 'param _id missing' unless @req.params['_id']
35
43
 
36
- return {
37
- :code => code,
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
- # 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
+ def delete
49
+ raise 'params missing' unless @req.params
50
+ raise 'param _id missing' unless @req.params['_id']
48
51
 
49
- unless respond_to.include? @req.format
50
- return format_response(403, 'format not allowed')
51
- end
52
+ @hash = @db.delete(class_name, @req.params['_id'])
53
+ end
52
54
 
53
- unless route_allowed?
54
- return format_response(403, 'not allowed')
55
- end
55
+ def to_json
56
+ @hash.to_json
57
+ end
56
58
 
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
59
+ def class_name
60
+ self.class.to_s.downcase
61
+ end
64
62
 
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')
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
- private
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
- if @req.params['_id']
113
- !forbid_actions.include? :find
114
- else
115
- !forbid_actions.include? :find_all
116
- end
76
+ :find
117
77
  when 'POST'
118
- !forbid_actions.include? :create
78
+ :create
119
79
  when 'PUT'
120
- !forbid_actions.include? :update
80
+ :update
121
81
  when 'DELETE'
122
- !forbid_actions.include? :delete
82
+ :delete
123
83
  else
124
- false
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