sinatra-chassis 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/.gitignore +6 -0
  2. data/Gemfile +3 -0
  3. data/LICENSE +7 -0
  4. data/README.md +19 -0
  5. data/Rakefile +1 -0
  6. data/bin/chassis +73 -0
  7. data/lib/sinatra/chassis.rb +213 -0
  8. data/lib/sinatra/chassis/file_manager.rb +151 -0
  9. data/lib/sinatra/chassis/helpers.rb +237 -0
  10. data/lib/sinatra/chassis/tasks.rb +7 -0
  11. data/lib/sinatra/tasks/assets.rake +40 -0
  12. data/lib/sinatra/tasks/chassis.rake +23 -0
  13. data/lib/sinatra/tasks/datamapper.rake +117 -0
  14. data/lib/sinatra/tasks/pony.rake +11 -0
  15. data/lib/sinatra/tasks/sinatra.rake +23 -0
  16. data/lib/sinatra/templates/chassis/.gitignore +6 -0
  17. data/lib/sinatra/templates/chassis/Gemfile +8 -0
  18. data/lib/sinatra/templates/chassis/README.md +4 -0
  19. data/lib/sinatra/templates/chassis/Rakefile +2 -0
  20. data/lib/sinatra/templates/chassis/app.rb +20 -0
  21. data/lib/sinatra/templates/chassis/config.ru +2 -0
  22. data/lib/sinatra/templates/chassis/public/favicon.ico +0 -0
  23. data/lib/sinatra/templates/chassis/public/robots.txt +3 -0
  24. data/lib/sinatra/templates/chassis/tmp/restart.txt +0 -0
  25. data/lib/sinatra/templates/chassis/views/layout.erb +18 -0
  26. data/lib/sinatra/templates/chassis/views/readme.erb +23 -0
  27. data/lib/sinatra/templates/datamapper/data/migrations/datamapper_migration.rb +13 -0
  28. data/lib/sinatra/templates/datamapper/data/seeds/seed.rb +1 -0
  29. data/lib/sinatra/templates/datamapper/models/datamapper.rb +8 -0
  30. data/lib/sinatra/templates/datamapper/settings/datamapper.rb +16 -0
  31. data/lib/sinatra/templates/datamapper/tests/models/datamapper_tests.rb +16 -0
  32. data/lib/sinatra/templates/pony/settings/pony.rb +27 -0
  33. data/lib/sinatra/templates/sinatra/routes/routes.rb +7 -0
  34. data/lib/sinatra/templates/sinatra/tests/routes/routes_tests.rb +17 -0
  35. data/lib/sinatra/views/error.erb +36 -0
  36. data/sinatra-chassis.gemspec +28 -0
  37. metadata +149 -0
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ .DS_Store
2
+ *.gem
3
+ .bundle
4
+ Gemfile.lock
5
+ pkg/*
6
+ .c9revisions
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (C) 2013 Jarrod Taylor, LLP.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,19 @@
1
+ ## Chassis
2
+
3
+ Chassis is a mutable framework extension for Sinatra that's designed not just to help you write less code, but to help you focus on less code.
4
+
5
+ gem install sinatra-chassis
6
+
7
+ ### Instructions
8
+
9
+ http://jarrodtaylor.github.com/sinatra-chassis/
10
+
11
+ ### License
12
+
13
+ Copyright (C) 2013 Screen Sized, LLP.
14
+
15
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/chassis ADDED
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'sinatra/chassis/file_manager'
5
+
6
+ # Sets the default switches
7
+ switches = {
8
+ git: false,
9
+ heroku: false,
10
+ bundler: true
11
+ }
12
+
13
+ # Internal: Parses command options and runs associated methods.
14
+ #
15
+ # Example
16
+ # ~: chassis -g -h ~/Projects/my_new_app
17
+ #
18
+ # Each command is self documenting.
19
+ options = OptionParser.new do |opt|
20
+ opt.banner = 'Options:'
21
+
22
+ opt.on('-g', '--git', 'Init a git repo, add the first commit') { switches[:git] = true }
23
+
24
+ opt.on('-h', '--heroku', 'Create a Heroku app') { switches[:heroku] = true }
25
+
26
+ opt.on('--skip-bundle', 'Don\'t run bundle install') { switches[:bundler] = false }
27
+
28
+ opt.parse!
29
+ end
30
+
31
+ # If app name is given, create application.
32
+ if ARGV[0]
33
+ app = ARGV[0]
34
+
35
+ unless File.exists? app
36
+ puts " Creating #{app}:"
37
+ puts LABELS[:add] + app
38
+ create_directory app
39
+ else
40
+ puts "#{app} already exists."
41
+ exit
42
+ end
43
+
44
+ copy_directory "#{TEMPLATES}/chassis", app
45
+
46
+ if switches[:bundler]
47
+ puts LABELS[:run] + 'bundle'
48
+ system "cd #{app} && bundle install"
49
+ end
50
+
51
+ puts LABELS[:run] + 'chmod -r 0755'
52
+ FileUtils.chmod_R 0755, app
53
+
54
+ if switches[:git]
55
+ puts LABELS[:run] + 'git'
56
+ system "cd #{app} && git init && git add . && git commit -m 'First!'"
57
+ end
58
+
59
+ if switches[:heroku]
60
+ puts LABELS[:run] + 'heroku'
61
+ system "cd #{app} && heroku create && git push heroku master"
62
+ end
63
+
64
+ puts "\n Next steps:\n cd #{app}\n ruby app.rb\n\n"
65
+ exit
66
+ end
67
+
68
+ # If script hasn't exited already, show help.
69
+ puts "The chassis command creates a new chassis app.\n\n"
70
+ puts "Usage:\n chassis [options] app_path\n\n"
71
+ puts "Example:\n chassis -g -h ~/Projects/my_app\n\n"
72
+ puts options
73
+ puts ''
@@ -0,0 +1,213 @@
1
+ require 'sinatra/base'
2
+
3
+ module Sinatra
4
+
5
+ # Public: Helpers used in the Chassis module.
6
+ # Can be overriden from an app.
7
+ module ChassisHelpers
8
+
9
+ # Public: Compares the request user agent against
10
+ # the mobile_user_agents setting Array items (should contain regexes).
11
+ #
12
+ # Example
13
+ #
14
+ # mobile_request?
15
+ # # => true
16
+ #
17
+ # Returns true/false.
18
+ def mobile_request?
19
+ settings.mobile_user_agents.any? { |agent| request.env['HTTP_USER_AGENT'] =~ agent }
20
+ end
21
+
22
+ # Public: Checks to see if a view template exists.
23
+ # It will check through all registered view directories.
24
+ #
25
+ # template - String of view template filename to look for
26
+ #
27
+ # Example
28
+ #
29
+ # view_template('show.haml')
30
+ # # => true
31
+ #
32
+ # Returns true/false.
33
+ def view_exists? template
34
+ Array(settings.views).each { |v| return true if File.exists?("#{v}/#{template}") }
35
+ false
36
+ end
37
+
38
+ # Public: Prepends the Sinatra find_template method to
39
+ # find .mobile templates if the mobile_views setting is true
40
+ # the request is from a mobile device.
41
+ #
42
+ # Example
43
+ #
44
+ # erb :my_view
45
+ #
46
+ # Renders the my_view.mobile.erb instead of my_view.erb.
47
+ def find_template views, name, engine, &block
48
+ name = "#{name}.mobile" if
49
+ (settings.mobile_views) &&
50
+ (mobile_request?) &&
51
+ (view_exists?("#{name}.mobile.#{@preferred_extension}"))
52
+ Array(views).each { |v| super(v, name, engine, &block) }
53
+ end
54
+
55
+ end
56
+
57
+ module Chassis
58
+
59
+ # Public: Requires all .rb files in a given directory or directories.
60
+ #
61
+ # *args - String(s) or Array of String paths to require
62
+ #
63
+ # Exmaple
64
+ #
65
+ # require_directory('routes', 'models')
66
+ #
67
+ # Returns nothing.
68
+ def require_directory *args
69
+ args = args.first if args.first.kind_of? Array
70
+ args.each do |directory|
71
+ Dir["./#{directory}/**/*.rb"].each { |file| require file }
72
+ end
73
+ end
74
+
75
+ # Public: Additions to the Sinatra app.
76
+ def self.registered(app)
77
+
78
+ # Public: Defines the default load path to be used with require_directory.
79
+ #
80
+ # Example
81
+ #
82
+ # require_directory(settings.load_path)
83
+ app.set :load_path, ['config', 'settings', 'helpers', 'libraries', 'models', 'controllers', 'routes']
84
+
85
+ # Public: Defines the default mobile user agents.
86
+ app.set :mobile_user_agents, [/iPhone/, /Android.*AppleWebKit/]
87
+
88
+ # Public: Turns on .mobile view templates.
89
+ app.enable :mobile_views
90
+
91
+ # Public: Determines where to load assets from.
92
+ app.set :assets_path, ['public']
93
+
94
+ # Public: Compiles .scss file to .css on request.
95
+ #
96
+ # Example
97
+ #
98
+ # <link rel="stylesheet" type="text/css" href="theme.css">
99
+ #
100
+ # Returns the compiled theme.scss, if it exists.
101
+ # Note that requests to public files bypass this handler.
102
+ app.get '*.css/?' do
103
+ file = params[:splat].first
104
+
105
+ found = false
106
+ type = nil
107
+
108
+ settings.assets_path.each do |path|
109
+ file.sub!("#{path}/", '') unless path == 'public'
110
+ if File.exists?("./#{path}#{file}.css")
111
+ found = "#{path}#{file}"
112
+ type = 'css'
113
+ break
114
+ end
115
+ if File.exists?("./#{path}#{file}.scss")
116
+ found = "#{path}#{file}"
117
+ type = 'scss'
118
+ break
119
+ end
120
+ end
121
+
122
+ if found
123
+ content_type 'text/css'
124
+ if type == 'css'
125
+ File.read "#{found}.css"
126
+ elsif type == 'scss'
127
+ scss found.to_sym, views: './'
128
+ end
129
+ else
130
+ pass
131
+ end
132
+ end
133
+
134
+ # Public: Compiles .coffee file to .js on request.
135
+ #
136
+ # Example
137
+ #
138
+ # <script type="text/javascript" src"script.js"></script>
139
+ #
140
+ # Returns the compiled script.coffee, if it exists.
141
+ # Note that requests to public files bypass this handler.
142
+ app.get '*.js/?' do
143
+ file = params[:splat].first
144
+
145
+ found = false
146
+ type = nil
147
+
148
+ settings.assets_path.each do |path|
149
+ file.sub!("#{path}/", '') unless path == 'public'
150
+ if File.exists?("./#{path}#{file}.js")
151
+ found = "#{path}#{file}"
152
+ type = 'js'
153
+ break
154
+ end
155
+ if File.exists?("./#{path}#{file}.coffee")
156
+ found = "#{path}#{file}"
157
+ type = 'coffee'
158
+ break
159
+ end
160
+ end
161
+
162
+ if found
163
+ content_type 'text/javascript'
164
+ if type == 'js'
165
+ File.read "#{found}.js"
166
+ elsif type == 'coffee'
167
+ coffee found.to_sym, views: './'
168
+ end
169
+ else
170
+ pass
171
+ end
172
+ end
173
+
174
+ # Public: Adds the internal Chassis views directory to the app.
175
+ # Used for finding the built in error template.
176
+ app.set :views, ['views', File.dirname(__FILE__) + '/views']
177
+
178
+ # Public: Turns on the catch all route in a not_found request.
179
+ app.enable :catch_all_route
180
+
181
+ # Public: Handles 404s.
182
+ #
183
+ # If there is no matching route handler, this will return a view template
184
+ # by matching the request path to a /views directory path and file. If
185
+ # no template is found, a 404 is called.
186
+ #
187
+ # In production, the 404 will render the production error template.
188
+ not_found do
189
+ if settings.catch_all_route?
190
+ view = request.path[1..-1]
191
+ Tilt.mappings.each do |m|
192
+ return send(m.first, view.to_sym) if view_exists?("#{view}.#{m.first}")
193
+ end
194
+ end
195
+ erb(:error, layout: false, locals: { code: '404', message: 'Not Found' }) if production?
196
+ end
197
+
198
+ # Public: Makes production errors prettier by rendering a built in template.
199
+ configure :production do
200
+ error(400) { erb :error, layout: false, locals: { code: '400', message: 'Bad Request' } }
201
+ error(401) { erb :error, layout: false, locals: { code: '401', message: 'Unauthorized' } }
202
+ error(403) { erb :error, layout: false, locals: { code: '403', message: 'Forbidden' } }
203
+ error(408) { erb :error, layout: false, locals: { code: '408', message: 'Request Timeout' } }
204
+ error(500) { erb :error, layout: false, locals: { code: '500', message: 'Internal Server Error' } }
205
+ error(502) { erb :error, layout: false, locals: { code: '502', message: 'Bad Gateway' } }
206
+ end
207
+ end
208
+
209
+ end
210
+
211
+ helpers ChassisHelpers
212
+ register Chassis
213
+ end
@@ -0,0 +1,151 @@
1
+ require 'paint'
2
+ require 'fileutils'
3
+ require 'erb'
4
+
5
+ # Public: Hash of colored and aligned Strings for displaying command actions.
6
+ # If interpolated, don't use any surrounding spaces.
7
+ LABELS = {
8
+ add: Paint[' add ', :green],
9
+ ignore: Paint[' ignore ', :blue],
10
+ overwrite: Paint[' overwrite ', :yellow],
11
+ remove: Paint[' remove ', :red],
12
+ run: Paint[' run ', :magenta]
13
+ }
14
+
15
+ # Public: String path location of the templates directory.
16
+ TEMPLATES = "#{File.dirname(__FILE__)}/../templates"
17
+
18
+ # Public: Asks the user if a file should be overwritten.
19
+ #
20
+ # file - Sting path of file in question
21
+ #
22
+ # Example
23
+ #
24
+ # overwritable? 'path/to/my/file.rb'
25
+ #
26
+ # Returns true or false based on user selection.
27
+ def overwritable? path
28
+ puts "#{path} already exists. Replace? (yes or no)"
29
+ decision = gets.strip!.downcase!
30
+ return false unless (decision == 'yes') || (decision == 'y')
31
+ return true
32
+ end
33
+
34
+ # Public: Adds to the end of a file.
35
+ #
36
+ # file - String path of file to add to
37
+ # text - text to add
38
+ #
39
+ # Example
40
+ #
41
+ # appent_to_file 'path/to/file.rb', 'Hello, world!'
42
+ #
43
+ # Returns nothing.
44
+ #
45
+ # Todo
46
+ #
47
+ # - Return true/false based on success.
48
+ def append_to_file file, text
49
+ File.open(file, 'a') {|f| f.write(text) }
50
+ end
51
+
52
+ # Public: Copies a file from one location to another.
53
+ # Asks the user of existing files should be overwritten.
54
+ #
55
+ # orignal_file - String path of the file to be copied
56
+ # new_file - Destination of the copied file
57
+ #
58
+ # Example
59
+ #
60
+ # copy_file 'path/to/original_file.rb', 'path/to/new/location.rb'
61
+ #
62
+ # Returns true if the file was copied, false if not.
63
+ def copy_file original_file, new_file
64
+ unless File.exists? new_file
65
+ puts LABELS[:add] + new_file
66
+ FileUtils.cp original_file, new_file
67
+ return true
68
+ else
69
+ if overwritable? new_file
70
+ puts LABELS[:overwrite] + new_file
71
+ FileUtils.cp original_file, new_file
72
+ return true
73
+ else
74
+ puts LABELS[:ignore] + new_file
75
+ return false
76
+ end
77
+ end
78
+ end
79
+
80
+ # Public: Copies a file using ERB to insert variables.
81
+ #
82
+ # template_file - String path of the template to be copied
83
+ # new_file - String path of the file to create from the template_file
84
+ # locals - Hash of variables to pass to the temlate_file
85
+ #
86
+ # Example
87
+ #
88
+ # copy_template "#{TEMPLATES}/path/to/template.rb",
89
+ # 'path/to/new/file.rb',
90
+ # { foo: 'bar' }
91
+ #
92
+ # Returns true if the template was copied, false if not.
93
+ def copy_template template_file, new_file, locals = {}
94
+ unless File.exists? new_file
95
+ puts LABELS[:add] + new_file
96
+ File.open(new_file, 'w') { |f| f.write( ERB.new(File.read(template_file)).result(binding) ) }
97
+ return true
98
+ else
99
+ if overwritable? new_file
100
+ puts LABELS[:overwrite] + new_file
101
+ File.open(new_file, 'w') { |f| f.write( ERB.new(File.read(template_file)).result(binding) ) }
102
+ return true
103
+ else
104
+ puts LABELS[:ignore] + new_file
105
+ return false
106
+ end
107
+ end
108
+ end
109
+
110
+ # Public: Creates a directory if it doesn't already exist.
111
+ #
112
+ # *args - path(s) as a String, multiple Strings, or an Array of Strings
113
+ #
114
+ # Examples
115
+ #
116
+ # create_directory 'path/to/directory'
117
+ # create_directory 'path/to/directory', 'path/to/other/directory
118
+ # create_directory ['path/to/directory', 'path/to/other/directory']
119
+ #
120
+ # Returns nothing.
121
+ #
122
+ # Todo
123
+ #
124
+ # - Return true/false based on success.
125
+ def create_directory *args
126
+ args = args.first if args.first.kind_of? Array
127
+ args.each { |dir| FileUtils.mkdir(dir) unless File.exists?(dir) }
128
+ end
129
+
130
+ # Public: Copies a directory (with contents) to another directory.
131
+ # If the new directory doesn't exist, it will be created.
132
+ #
133
+ # original_dir - String path of the directory to be copied from
134
+ # new_dir - String path of directory to be copied to
135
+ #
136
+ # Example
137
+ #
138
+ # copy_directory 'path/to/original/directory', 'path/to/new/directory'
139
+ #
140
+ # Returns nothing.
141
+ #
142
+ # Todo
143
+ #
144
+ # - Return true/false based on success.
145
+ def copy_directory original_dir, new_dir
146
+ create_directory new_dir
147
+ Dir.glob("#{original_dir}/**/{*,.gitignore}").each do |path|
148
+ new_path = path.sub original_dir, new_dir
149
+ File.directory?(path) ? create_directory(new_path) : copy_file(path, new_path)
150
+ end
151
+ end