sinatra-chassis 1.0.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 (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
@@ -0,0 +1,237 @@
1
+ require 'sinatra/base'
2
+ require 'rack-flash'
3
+
4
+ # Public: Adds helpers
5
+ module Sinatra
6
+
7
+ module ChassisExtraHelpers
8
+ # Public: Checks if the argument can be evaluated numerically.
9
+ #
10
+ # Example
11
+ #
12
+ # is_numeric?('1')
13
+ # # => true
14
+ #
15
+ # is_numeric?('hello')
16
+ # # => false
17
+ #
18
+ # Returns true/false.
19
+ def numeric? x
20
+ true if Float(x) rescue false
21
+ end
22
+
23
+ # Public: Truncates a String or Number.
24
+ #
25
+ # x - String or Number to truncate
26
+ # word_count - Integer number of words to return if x is a String (default: 100)
27
+ # end_string - String appended to the end of the returned String if
28
+ # the original x String is longer than word_count (default: '...')
29
+ # decimal - Integer number of maximum places after decimal if x is a Number (default: 1)
30
+ # trailing_zeros - Boolean to decide if a returned Number should keep the
31
+ # trailing 0's as a String (default: false)
32
+ #
33
+ # Examples
34
+ #
35
+ # truncate('Lorem ipsum dolor sit amet.', word_count: 3, end_string: '...')
36
+ # # => 'Lorem ipsum dolor...'
37
+ #
38
+ # truncate(1.234000, decimal: 1)
39
+ # # => 1.2
40
+ # truncate(1.234000, decimal: 5)
41
+ # # => 1.234
42
+ # truncate(1.234000, decimal: 5, trailing_zeros: true)
43
+ # # => '1.23400'
44
+ #
45
+ # Returns a String or Float.
46
+ def truncate x, options = {}
47
+ options[:word_count] ||= 100
48
+ options[:end_string] ||= '...'
49
+ options[:decimal] ||= 2
50
+ options[:trailing_zeros] ||= false
51
+
52
+ if x.kind_of? String
53
+ return if x == nil
54
+ words = x.split()
55
+ return words[0..(options[:word_count]-1)].join(' ') + (words.length > options[:word_count] ? options[:end_string] : '')
56
+ elsif is_numeric? x
57
+ number = "%.#{options[:decimal]}f" % x.to_f
58
+ number = number.to_f unless options[:trailing_zeros]
59
+ return number
60
+ end
61
+ end
62
+
63
+ # Public: Uppercases the first letter of each word.
64
+ #
65
+ # Example
66
+ #
67
+ # titleize('hello world')
68
+ # # => 'Hello World'
69
+ #
70
+ # Returns a String.
71
+ def titleize x
72
+ title = ''
73
+ x.to_s.split(' ').each { |s| title << s.capitalize + ' ' }
74
+ title
75
+ end
76
+
77
+ # Public: Compares a string to the request path.
78
+ #
79
+ # path - String to compare against the request path
80
+ #
81
+ # Exmaple
82
+ #
83
+ # Requested URL: http://localhost:4567/hello/world
84
+ # active('hello')
85
+ # # => 'active'
86
+ # active('goodbye')
87
+ # # => ''
88
+ #
89
+ # Returns a Sting: 'active' if there's a match, '' if not.
90
+ def active path
91
+ path = Array[path] unless path.kind_of? Array
92
+ match = false
93
+ path.each { |p| match = true if request.path_info.include?(p) }
94
+ 'active' if match
95
+ end
96
+
97
+ # Public: Displays an alert unless flash[:alert] if nil.
98
+ # flash[:alert] empties itself after the first request after it's set.
99
+ # To use, set flash[:alert] to a String.
100
+ #
101
+ # Example
102
+ # <%= alert %>
103
+ #
104
+ # Returns a div with an id of 'alert' and containing the contents
105
+ # of flash[:alert], or if flash[:alert] if nil, returns nothing.
106
+ def alert
107
+ "<div id='alert'>#{flash[:alert]}</div>" if flash[:alert]
108
+ end
109
+
110
+ # Public: Hides an HTML element.
111
+ # Useful in combination with inline true/false comparators.
112
+ #
113
+ # Example
114
+ #
115
+ # <div style="<%= hidden unless session[:user] %>">Hello, world!</div>
116
+ #
117
+ # Returns a String of CSS.
118
+ def hidden
119
+ 'display: none;'
120
+ end
121
+
122
+ # Public: Converts a Date to select form fields.
123
+ # All generated fields have classes of month_select, day_select, or year_select.
124
+ # None of the options are required, but they are all recommended.
125
+ #
126
+ # select_name - name attr for fields, appended with '_day', '_month', or '_year'
127
+ # select_id - id attr for fields, appended with '_day', '_month', or '_year'
128
+ # select_class - class attr for fields, appended with '_day', '_month', or '_year'
129
+ # start_year - first year to use in year select (default: 3 years ago)
130
+ # end_year - last year to use in year select (default: 3 years from now)
131
+ # day_first - Boolean to show the day before the month (default: false)
132
+ # month_name - Boolean to display month names (default: false)
133
+ #
134
+ # Example
135
+ #
136
+ # date_select(
137
+ # DateTime.now
138
+ # select_class: 'your_class',
139
+ # select_id: 'your_id',
140
+ # select_name: 'your_name',
141
+ # start_year: 1999,
142
+ # end_year: 2021,
143
+ # day_first: true,
144
+ # month_name: false
145
+ # )
146
+ #
147
+ # Returns select fields as a String.
148
+ def date_select date, options = {}
149
+ options[:select_name] ||= ''
150
+ options[:select_id] ||= ''
151
+ options[:select_class] ||= ''
152
+
153
+ unless options[:select_id] == ''
154
+ day_id = " id='#{options[:select_id]}_day'"
155
+ month_id = " id='#{options[:select_id]}_month'"
156
+ year_id = " id='#{options[:select_id]}_year'"
157
+ else
158
+ day_id = ''
159
+ month_id = ''
160
+ year_id = ''
161
+ end
162
+
163
+ unless options[:select_name] == ''
164
+ day_name = " name='#{options[:select_name]}_day'"
165
+ month_name = " name='#{options[:select_name]}_month'"
166
+ year_name = " name='#{options[:select_name]}_year'"
167
+ else
168
+ day_name = ''
169
+ month_name = ''
170
+ year_name = ''
171
+ end
172
+
173
+ options[:day_first] ||= false
174
+ options[:start_year] ||= Time.now.strftime('%Y').to_i - 3
175
+ options[:end_year] ||= Time.now.strftime('%Y').to_i + 3
176
+ options[:month_name] ||= false
177
+
178
+ options[:start_year] = date.strftime('%Y').to_i if date.strftime('%Y').to_i < options[:start_year]
179
+ options[:end_year] = date.strftime('%Y').to_i if date.strftime('%Y').to_i > options[:end_year]
180
+
181
+ months = [
182
+ { num: '01', name: 'January' },
183
+ { num: '02', name: 'February' },
184
+ { num: '03', name: 'March' },
185
+ { num: '04', name: 'April' },
186
+ { num: '05', name: 'May' },
187
+ { num: '06', name: 'June' },
188
+ { num: '07', name: 'July' },
189
+ { num: '08', name: 'August' },
190
+ { num: '09', name: 'September' },
191
+ { num: '10', name: 'October' },
192
+ { num: '11', name: 'November' },
193
+ { num: '12', name: 'December' }
194
+ ]
195
+
196
+ day = "<select class='day_select #{options[:select_class]}'#{day_id}#{day_name}'>"
197
+ (1..31).each do |d|
198
+ day << "<option value='#{d}' #{'selected' if d == date.strftime('%d').to_i}>#{d}</option>"
199
+ end
200
+ day << "</select>"
201
+
202
+ month = "<select class='month_select #{options[:select_class]}'#{month_id}#{month_name}>"
203
+ months.each do |m|
204
+ options[:month_name] ? d = m[:name] : d = m[:num]
205
+ month << "<option value='#{m[:num]}' #{'selected' if m[:num] == date.strftime('%m').to_i}>#{d}</option>"
206
+ end
207
+ month << "</select>"
208
+
209
+ year = "<select class='year_select #{options[:select_class]}'#{year_id}#{year_name}>"
210
+ (options[:start_year]..options[:end_year]).each do |y|
211
+ year << "<option value='#{y}' #{'selected' if y == date.strftime('%Y').to_i}>#{y}</option>"
212
+ end
213
+ year << "</select>"
214
+
215
+ if options[:day_first]
216
+ return "#{day} #{month} #{year}"
217
+ else
218
+ return "#{month} #{day} #{year}"
219
+ end
220
+ end
221
+
222
+ end
223
+
224
+ module ChassisExtras
225
+
226
+ # Adds Rack::Flash to the app (requires sessions)
227
+ def self.registered(app)
228
+ app.enable :sessions
229
+ app.set :session_secret, [*('A'..'Z')].sample(40).join if app.session_secret.nil?
230
+ use Rack::Flash
231
+ end
232
+
233
+ end
234
+
235
+ helpers ChassisExtraHelpers
236
+ register ChassisExtras
237
+ end
@@ -0,0 +1,7 @@
1
+ # Require this script in app Rakefiles to import the Chassis file_manager,
2
+ # the Chassis app rake tasks, and the tasks in the app /tasks directory.
3
+
4
+ require "#{File.dirname(__FILE__)}/file_manager"
5
+
6
+ Dir[File.join(File.dirname(__FILE__) + "/../tasks/**/*.rake")].each { |file| import file }
7
+ Dir["./tasks/**/*.rake"].each { |file| import file }
@@ -0,0 +1,40 @@
1
+ namespace :assets do
2
+
3
+ desc 'Compile .coffee and .sass files in /public'
4
+ task :precompile do
5
+ settings.assets_path.each do |path|
6
+ copy_directory("./#{path}", "./public/#{path}") unless path == 'public'
7
+ end
8
+ Dir.glob("./public/**/*.coffee").each do |asset|
9
+ File.open(asset.gsub('.coffee', '.js'), 'w') do |f|
10
+ f.write(CoffeeScript.compile(File.read(asset)))
11
+ end
12
+ end
13
+ Dir.glob("./public/**/*.scss").each do |asset|
14
+ File.open(asset.gsub('.scss', '.css'), 'w') do |f|
15
+ f.write(Sass::Engine.for_file(asset, {}).render)
16
+ end
17
+ end
18
+ settings.assets_path.each do |path|
19
+ unless path == 'public'
20
+ Dir.glob("./public/#{path}/**/*.{coffee,scss}").each do |asset|
21
+ File.delete(asset)
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ desc 'Remove compiled assets'
28
+ task :decompile do
29
+ settings.assets_path.each do |path|
30
+ FileUtils.rm_rf("./public/#{path}") unless path == 'public'
31
+ end
32
+ Dir.glob("./public/**/*.coffee").each do |asset|
33
+ File.delete(asset.gsub('.coffee', '.js')) if File.exists?(asset.gsub('.coffee', '.js'))
34
+ end
35
+ Dir.glob("./public/**/*.scss").each do |asset|
36
+ File.delete(asset.gsub('.scss', '.css')) if File.exists?(asset.gsub('.scss', '.css'))
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,23 @@
1
+ namespace :chassis do
2
+
3
+ desc 'Run app in an IRB session'
4
+ task :irb do
5
+ require 'irb'
6
+ ARGV.clear
7
+ IRB.start
8
+ end
9
+
10
+ namespace :run do
11
+
12
+ desc 'Run one or all /tests scripts'
13
+ task :test, :file do |t, args|
14
+ if args.file == nil
15
+ Dir["./tests/**/*.rb"].each { |file| require file }
16
+ else
17
+ require "./tests/#{args.file}"
18
+ end
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,117 @@
1
+ namespace :setup do
2
+
3
+ desc 'Set up DataMapper'
4
+ task :datamapper do
5
+ create_directory './settings'
6
+ append_to_file './Gemfile', "\ngem 'data_mapper', '~> 1.2.0'"
7
+ append_to_file './Gemfile', "\ngem 'dm-sqlite-adapter', '~> 1.2.0'"
8
+ append_to_file './Gemfile', "\n# gem 'dm-mysql-adapter', '~> 1.2.0'"
9
+ append_to_file './Gemfile', "\n# gem 'dm-postgres-adapter', '~> 1.2.0'\n"
10
+ append_to_file './app.rb', "\nDataMapper.finalize\n"
11
+ copy_file "#{TEMPLATES}/datamapper/settings/datamapper.rb",
12
+ "./settings/datamapper.rb"
13
+ end
14
+
15
+ end
16
+
17
+ namespace :dm do
18
+
19
+ def create_dm_path
20
+ if DataMapper.repository.adapter.options[:path].include? 'sqlite'
21
+ db = DataMapper.repository.adapter.options[:path].split('/').last
22
+ create_directory DataMapper.repository.adapter.options[:path].gsub(db, '')
23
+ end
24
+ end
25
+
26
+ namespace :add do
27
+
28
+ desc 'Add a data migration' if defined? DataMapper
29
+ task :migration, :name do |t, args|
30
+ if args.name == nil
31
+ puts 'You must define a migration name.'
32
+ puts 'Example: rake add:migration[my_migration]'
33
+ exit
34
+ end
35
+ create_directory './data', './data/migrations'
36
+ t = Time.now.strftime("%Y%m%d%H%M%S")
37
+ copy_template "#{TEMPLATES}/datamapper/data/migrations/datamapper_migration.rb",
38
+ "./data/migrations/#{t}_#{args.name}.rb",
39
+ { t: t, migration: args.name }
40
+ end
41
+
42
+ desc 'Add a model' if defined? DataMapper
43
+ task :model, :name do |t, args|
44
+ if args.name == nil
45
+ puts 'You must define a model name.'
46
+ puts 'Example: rake add:model[my_model]'
47
+ exit
48
+ end
49
+ create_directory './models', './tests', './tests/models'
50
+ copy_template "#{TEMPLATES}/datamapper/models/datamapper.rb",
51
+ "./models/#{args.name}.rb",
52
+ { model: args.name }
53
+ copy_template "#{TEMPLATES}/datamapper/tests/models/datamapper_tests.rb",
54
+ "./tests/models/#{args.name}_tests.rb",
55
+ { model: args.name }
56
+ end
57
+
58
+ desc 'Add a seed data script' if defined? DataMapper
59
+ task :seed, :name do |t, args|
60
+ if args.name == nil
61
+ puts 'You must define a seed file name.'
62
+ puts 'Example: rake add:seed[my_seed_script]'
63
+ exit
64
+ end
65
+ create_directory './data', './data/seeds'
66
+ copy_template "#{TEMPLATES}/datamapper/data/seeds/seed.rb",
67
+ "./data/seeds/#{args.name}.rb"
68
+ end
69
+
70
+ end
71
+
72
+ desc 'Auto upgrade one or all models' if defined? DataMapper
73
+ task :upgrade, :model do |t, args|
74
+ create_dm_path
75
+ args.model == nil ? DataMapper.auto_upgrade! : args.model.constantize.auto_upgrade!
76
+ end
77
+
78
+ desc 'Auto migrate one or all models' if defined? DataMapper
79
+ task :migrate, :model do |t, args|
80
+ create_dm_path
81
+ args.model == nil ? DataMapper.auto_migrate! : args.model.constantize.auto_migrate!
82
+ end
83
+
84
+ namespace :migrate do
85
+
86
+ desc 'Migrate up to a specific migration number' if defined? DataMapper
87
+ task :up, :number do |t, args|
88
+ create_dm_path
89
+ require 'dm-migrations/migration_runner'
90
+ Dir['./data/migrations/*.rb'].each { |m| require m }
91
+ args.number == nil ? migrate_up! : migrate_up!(args.number)
92
+ end
93
+
94
+ desc 'Migrate down to a specific migration number' if defined? DataMapper
95
+ task :down, :number do |t, args|
96
+ create_dm_path
97
+ require 'dm-migrations/migration_runner'
98
+ Dir['./data/migrations/*.rb'].each { |m| require m }
99
+ args.number == nil ? migrate_down! : migrate_down!(args.number)
100
+ end
101
+
102
+ end
103
+
104
+ namespace :run do
105
+
106
+ desc 'Run one or all /data/seeds scripts' if defined? DataMapper
107
+ task :seed, :file do |t, args|
108
+ if args.file == nil
109
+ Dir["./data/seeds/**/*.rb"].each { |file| require file }
110
+ else
111
+ require "./data/seeds/#{args.file}"
112
+ end
113
+ end
114
+
115
+ end
116
+
117
+ end
@@ -0,0 +1,11 @@
1
+ namespace :setup do
2
+
3
+ desc 'Set up Pony'
4
+ task :pony do
5
+ create_directory './settings'
6
+ append_to_file './Gemfile', "\ngem 'pony', '~> 1.4'\n"
7
+ copy_file "#{TEMPLATES}/pony/settings/pony.rb",
8
+ "./settings/pony.rb"
9
+ end
10
+
11
+ end
@@ -0,0 +1,23 @@
1
+ namespace :sinatra do
2
+
3
+ namespace :add do
4
+
5
+ desc 'Add a namespaced /routes file'
6
+ task :routes, :namespace do |t, args|
7
+ if args.namespace == nil
8
+ puts 'You must define a route namespace.'
9
+ puts 'Example: rake sinatra:add:routes[my_routes]'
10
+ exit
11
+ end
12
+ create_directory './routes', './tests', './tests/routes'
13
+ copy_template "#{TEMPLATES}/sinatra/routes/routes.rb",
14
+ "./routes/#{args.namespace}.rb",
15
+ { namespace: args.namespace }
16
+ copy_template "#{TEMPLATES}/sinatra/tests/routes/routes_tests.rb",
17
+ "./tests/routes/#{args.namespace}_tests.rb",
18
+ { namespace: args.namespace }
19
+ end
20
+
21
+ end
22
+
23
+ end