ki 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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