ditty 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.pryrc +2 -0
  4. data/.rubocop.yml +1 -1
  5. data/.travis.yml +5 -4
  6. data/CNAME +1 -0
  7. data/Dockerfile +18 -0
  8. data/Gemfile.ci +0 -2
  9. data/Rakefile +2 -2
  10. data/_config.yml +1 -0
  11. data/config.ru +4 -4
  12. data/ditty.gemspec +9 -3
  13. data/docs/CNAME +1 -0
  14. data/docs/_config.yml +1 -0
  15. data/docs/index.md +34 -0
  16. data/exe/ditty +2 -0
  17. data/lib/ditty.rb +4 -2
  18. data/lib/ditty/cli.rb +28 -4
  19. data/lib/ditty/components/{app.rb → ditty.rb} +19 -14
  20. data/lib/ditty/controllers/{application.rb → application_controller.rb} +58 -29
  21. data/lib/ditty/controllers/{audit_logs.rb → audit_logs_controller.rb} +2 -2
  22. data/lib/ditty/controllers/{auth.rb → auth_controller.rb} +17 -16
  23. data/lib/ditty/controllers/{component.rb → component_controller.rb} +19 -18
  24. data/lib/ditty/controllers/{main.rb → main_controller.rb} +6 -2
  25. data/lib/ditty/controllers/roles_controller.rb +23 -0
  26. data/lib/ditty/controllers/{user_login_traits.rb → user_login_traits_controller.rb} +4 -3
  27. data/lib/ditty/controllers/{users.rb → users_controller.rb} +11 -10
  28. data/lib/ditty/db.rb +4 -3
  29. data/lib/ditty/emails/base.rb +5 -2
  30. data/lib/ditty/generators/crud_generator.rb +104 -0
  31. data/lib/ditty/generators/migration_generator.rb +26 -0
  32. data/lib/ditty/generators/project_generator.rb +51 -0
  33. data/lib/ditty/helpers/component.rb +2 -1
  34. data/lib/ditty/helpers/pundit.rb +20 -4
  35. data/lib/ditty/helpers/response.rb +20 -13
  36. data/lib/ditty/helpers/views.rb +7 -3
  37. data/lib/ditty/listener.rb +5 -3
  38. data/lib/ditty/memcached.rb +8 -0
  39. data/lib/ditty/middleware/accept_extension.rb +2 -2
  40. data/lib/ditty/middleware/error_catchall.rb +2 -2
  41. data/lib/ditty/models/base.rb +4 -0
  42. data/lib/ditty/models/role.rb +1 -0
  43. data/lib/ditty/models/user.rb +14 -1
  44. data/lib/ditty/policies/role_policy.rb +1 -1
  45. data/lib/ditty/policies/user_login_trait_policy.rb +1 -1
  46. data/lib/ditty/services/authentication.rb +11 -10
  47. data/lib/ditty/services/email.rb +8 -4
  48. data/lib/ditty/services/logger.rb +1 -1
  49. data/lib/ditty/tasks/ditty.rake +17 -0
  50. data/lib/ditty/tasks/omniauth-ldap.rake +2 -2
  51. data/lib/ditty/templates/.gitignore +5 -0
  52. data/lib/ditty/templates/.rspec +2 -0
  53. data/lib/ditty/templates/.rubocop.yml +7 -0
  54. data/lib/ditty/templates/Rakefile +12 -0
  55. data/lib/ditty/templates/application.rb +12 -0
  56. data/lib/ditty/templates/config.ru +37 -0
  57. data/lib/ditty/templates/controller.rb.erb +58 -0
  58. data/lib/ditty/templates/env.example +4 -0
  59. data/lib/ditty/templates/lib/project.rb.erb +5 -0
  60. data/lib/ditty/templates/migration.rb.erb +7 -0
  61. data/lib/ditty/templates/model.rb.erb +26 -0
  62. data/lib/ditty/templates/pids/.empty_directory +0 -0
  63. data/lib/ditty/templates/policy.rb.erb +48 -0
  64. data/lib/ditty/templates/public/css/sb-admin-2.min.css +10 -0
  65. data/lib/ditty/templates/public/js/sb-admin-2.min.js +7 -0
  66. data/lib/ditty/templates/settings.yml.erb +18 -0
  67. data/lib/ditty/templates/sidekiq.rb +18 -0
  68. data/lib/ditty/templates/sidekiq.yml +9 -0
  69. data/lib/ditty/templates/spec_helper.rb +43 -0
  70. data/lib/ditty/templates/type.rb.erb +21 -0
  71. data/lib/ditty/templates/views/display.haml.tt +20 -0
  72. data/lib/ditty/templates/views/edit.haml.tt +10 -0
  73. data/lib/ditty/templates/views/form.haml.tt +11 -0
  74. data/lib/ditty/templates/views/index.haml.tt +29 -0
  75. data/lib/ditty/templates/views/new.haml.tt +10 -0
  76. data/lib/ditty/version.rb +1 -1
  77. data/lib/rubocop/cop/ditty/call_services_directly.rb +2 -2
  78. data/migrate/20181209_add_user_login_traits.rb +4 -4
  79. data/migrate/20190220_add_parent_id_to_roles.rb +9 -0
  80. data/public/css/styles.css +13 -0
  81. data/public/js/scripts.js +1 -0
  82. data/views/404.haml +2 -4
  83. data/views/audit_logs/index.haml +32 -34
  84. data/views/auth/forgot_password.haml +27 -16
  85. data/views/auth/identity.haml +14 -13
  86. data/views/auth/ldap.haml +2 -2
  87. data/views/auth/login.haml +22 -17
  88. data/views/auth/register.haml +19 -18
  89. data/views/auth/register_identity.haml +27 -12
  90. data/views/auth/reset_password.haml +2 -2
  91. data/views/blank.haml +42 -0
  92. data/views/index.haml +1 -1
  93. data/views/layout.haml +37 -30
  94. data/views/partials/content_tag.haml +0 -0
  95. data/views/partials/delete_form.haml +1 -1
  96. data/views/partials/filter_control.haml +1 -1
  97. data/views/partials/footer.haml +5 -5
  98. data/views/partials/form_control.haml +19 -12
  99. data/views/partials/navitems.haml +44 -0
  100. data/views/partials/notifications.haml +12 -8
  101. data/views/partials/pager.haml +17 -17
  102. data/views/partials/search.haml +6 -7
  103. data/views/partials/sidebar.haml +15 -37
  104. data/views/partials/topbar.haml +68 -0
  105. data/views/roles/display.haml +27 -6
  106. data/views/roles/edit.haml +3 -3
  107. data/views/roles/form.haml +1 -0
  108. data/views/roles/index.haml +23 -16
  109. data/views/roles/new.haml +2 -2
  110. data/views/user_login_traits/display.haml +4 -4
  111. data/views/user_login_traits/edit.haml +3 -3
  112. data/views/user_login_traits/index.haml +4 -4
  113. data/views/user_login_traits/new.haml +2 -2
  114. data/views/users/display.haml +11 -12
  115. data/views/users/edit.haml +3 -3
  116. data/views/users/form.haml +0 -0
  117. data/views/users/index.haml +31 -24
  118. data/views/users/login_traits.haml +6 -8
  119. data/views/users/new.haml +2 -2
  120. data/views/users/profile.haml +13 -13
  121. metadata +143 -15
  122. data/lib/ditty/controllers/roles.rb +0 -13
  123. data/views/partials/navbar.haml +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2b391296636a3f248171d3d71ca4c11466b8cce56f8814c271f2352e241da297
4
- data.tar.gz: 8b136a384187ea59d6d8caa8f46f3dcc7a4a72939ba924ddff0eb8a332828aa1
3
+ metadata.gz: 35f3891fe07db1d74d92de59cbcf9ebde20c7aa9f5fdc995a5bed98445ac38de
4
+ data.tar.gz: 2ed19a9d156c4a043aa3d29b8ad070ed70da16637a88577ef74630734038868e
5
5
  SHA512:
6
- metadata.gz: 8102d97c1b3516e4f922600055a22b5bff5293dd69fbcb92a5cd233ad0e9f2e52fc6f091e05aebcee9e1dd610e76b0049db29b1eccfd54ff09f794325156cf68
7
- data.tar.gz: c1ad5e59438e58fc6dbc34d5d2a95b1c5da4a0ccb88481fc15b9dd5942ece2d7525adcf52d3d520f9fd2c91dff65829d24a27ad8fb60d66889ac6f9b983c2fba
6
+ metadata.gz: b11cb4cdab8e3afa910750884a5129becfe68202f779a35011e368a3d872724a41d2b3bd90b06485fdbdea740fbbe1c7165a8da50095ab7c7d767c28c2595185
7
+ data.tar.gz: 9e06c150bc6fd18dcc564dae5cf43bc3d9a5327541df1d64dd7b6f305381d83102ef1c9105ae4a9bcfe82cfa11881eda1fb93ec2321bd549072d92c2ee0c4acb
data/.gitignore CHANGED
@@ -14,3 +14,5 @@ vendor
14
14
  *.db
15
15
  /Gemfile.dev.lock
16
16
  migrations
17
+ /gems.*
18
+ .env
data/.pryrc CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  if defined?(PryByebug)
2
4
  Pry.commands.alias_command 'c', 'continue'
3
5
  Pry.commands.alias_command 's', 'step'
@@ -1,7 +1,7 @@
1
1
  require: rubocop-rspec
2
2
 
3
3
  AllCops:
4
- TargetRubyVersion: 2.3
4
+ TargetRubyVersion: 2.7
5
5
  Metrics/LineLength:
6
6
  Max: 120
7
7
  Layout/LeadingCommentSpace:
@@ -1,10 +1,11 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.6.0
5
- - 2.5.3
6
- - 2.4.5
7
- - 2.3.8
4
+ - 2.7
5
+ - 2.6
6
+ - 2.5
7
+ - 2.4
8
+ - 2.3
8
9
  gemfile: Gemfile.ci
9
10
  env:
10
11
  global:
data/CNAME ADDED
@@ -0,0 +1 @@
1
+ ditty.io
@@ -0,0 +1,18 @@
1
+ FROM ruby:2.5.3-alpine3.8
2
+ LABEL maintainer: "Sergey Shkarupa <s.shkarupa@gmail.com>"
3
+
4
+ RUN apk add --no-cache \
5
+ build-base \
6
+ less \
7
+ git \
8
+ libxml2-dev \
9
+ libxslt-dev \
10
+ sqlite-dev \
11
+ sqlite-doc \
12
+ sqlite-libs \
13
+ && gem install bundler:1.17.3
14
+
15
+ WORKDIR /usr/src/app
16
+
17
+ COPY . ./
18
+ RUN bundle install --jobs=$(nproc) --no-cache --clean
data/Gemfile.ci CHANGED
@@ -4,8 +4,6 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  gem 'faker'
7
- gem 'rubocop'
8
- gem 'rubocop-rspec'
9
7
  gem 'simplecov', '~> 0.13.0'
10
8
  gem 'sqlite3'
11
9
 
data/Rakefile CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  require 'rake'
4
4
  require 'ditty'
5
- require 'ditty/components/app'
5
+ require 'ditty/components/ditty'
6
6
 
7
- Ditty.component :app
7
+ Ditty.component :ditty
8
8
 
9
9
  Ditty::Components.tasks
10
10
  require 'bundler/gem_tasks' if File.exist? 'ditty.gemspec'
@@ -0,0 +1 @@
1
+ theme: jekyll-theme-architect
data/config.ru CHANGED
@@ -6,14 +6,14 @@ use Rack::Session::Cookie,
6
6
  # :secure=>!TEST_MODE, # Uncomment if only allowing https:// access
7
7
  secret: File.read('.session_secret')
8
8
 
9
- require 'ditty/components/app'
10
- Ditty.component :app
9
+ require 'ditty/components/ditty'
10
+ Ditty.component :ditty
11
11
 
12
12
  require 'ditty/services/authentication'
13
13
  use OmniAuth::Builder do
14
- Ditty::Services::Authentication.config.each do |prov, config|
14
+ ::Ditty::Services::Authentication.config.each do |prov, config|
15
15
  provider prov, *config[:arguments]
16
16
  end
17
17
  end
18
18
 
19
- run Rack::URLMap.new Ditty::Components.routes
19
+ run Rack::URLMap.new ::Ditty::Components.routes
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- lib = File.expand_path('../lib', __FILE__)
3
+ lib = File.expand_path('lib', __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require 'ditty/version'
6
6
 
7
7
  Gem::Specification.new do |spec|
8
8
  spec.name = 'ditty'
9
- spec.version = Ditty::VERSION
9
+ spec.version = ::Ditty::VERSION
10
10
  spec.authors = ['Jurgens du Toit']
11
11
  spec.email = ['jrgns@jadeit.co.za']
12
12
 
@@ -26,12 +26,18 @@ Gem::Specification.new do |spec|
26
26
  spec.add_development_dependency 'rack-test'
27
27
  spec.add_development_dependency 'racksh'
28
28
  spec.add_development_dependency 'rspec', '~> 3.0'
29
+ spec.add_development_dependency 'rubocop'
30
+ spec.add_development_dependency 'rubocop-performance'
31
+ spec.add_development_dependency 'rubocop-rspec'
32
+ spec.add_development_dependency 'rubocop-sequel'
33
+ spec.add_development_dependency 'rubocop-thread_safety'
29
34
  spec.add_development_dependency 'timecop'
30
35
 
31
36
  spec.add_dependency 'activesupport', '>= 3'
32
37
  spec.add_dependency 'bcrypt', '~> 3.1'
33
38
  spec.add_dependency 'browser', '~> 2.5'
34
- spec.add_dependency 'haml', '~> 5.0'
39
+ spec.add_dependency 'dotenv', '>= 2'
40
+ spec.add_dependency 'haml', '~> 5.1.2'
35
41
  spec.add_dependency 'logger', '~> 1.0'
36
42
  spec.add_dependency 'mail', '>= 1.7'
37
43
  spec.add_dependency 'oga', '>= 2.14'
@@ -0,0 +1 @@
1
+ ditty.io
@@ -0,0 +1 @@
1
+ theme: jekyll-theme-architect
@@ -0,0 +1,34 @@
1
+ # Ditty.io
2
+
3
+ Ditty is a Web Application Framework built on top of the [Sinatra](http://sinatrarb.com/) framework.
4
+
5
+ ## Installation
6
+
7
+ Add these lines to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'ditty'
11
+ gem 'sqlite3'
12
+ ```
13
+
14
+ You can replace `sqlite3` with a DB adapter of your choice.
15
+
16
+ And then execute:
17
+
18
+ ```bash
19
+ bundle install
20
+ ```
21
+
22
+ Or install it yourself as:
23
+
24
+ ```bash
25
+ gem install ditty
26
+ ```
27
+
28
+ ## Usage
29
+
30
+ 1. Add the components to your rack config file. See the included [`config.ru`](https://github.com/EagerELK/ditty/blob/master/config.ru) file for an example setup
31
+ 2. Set the DB connection as the `DATABASE_URL` ENV variable: `DATABASE_URL=sqlite://development.db`
32
+ 3. Prepare the Ditty folder: `bundle exec ditty prep`
33
+ 3. Run the Ditty migrations: `bundle exec ditty migrate`
34
+ 4. Run the Ditty server: `bundle exec ditty server`
data/exe/ditty CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
2
4
  require 'ditty/cli'
3
5
 
4
6
  Ditty::CLI.start
@@ -62,7 +62,9 @@ module Ditty
62
62
  h = @components
63
63
  unless (component = h[name])
64
64
  require "ditty/components/#{name}"
65
- raise ComponentError, "Component #{name} did not register itself correctly in Ditty::Components" unless (component = h[name])
65
+ unless (component = h[name])
66
+ raise ComponentError, "Component #{name} did not register itself correctly in Ditty::Components"
67
+ end
66
68
  end
67
69
  component
68
70
  end
@@ -76,7 +78,7 @@ module Ditty
76
78
  #
77
79
  # Ditty::Components.register_component(:component_name, ComponentModule)
78
80
  def self.register_component(name, mod)
79
- Ditty::Services::Logger.instance.info "Registering #{mod} as #{name}"
81
+ ::Ditty::Services::Logger.info "Registering #{mod} as #{name}"
80
82
  @components[name] = mod
81
83
  end
82
84
 
@@ -1,24 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # https://nandovieira.com/creating-generators-and-executables-with-thor
4
- require 'dotenv/load'
4
+ require 'dotenv/load' rescue LoadError # rubocop:disable Style/RescueModifier - Ignore dotenv/load errors
5
5
  require 'thor'
6
6
  require 'rack'
7
7
  require 'rake'
8
+ require 'ditty/db' if ENV['DATABASE_URL']
9
+ require 'ditty/generators/crud_generator'
10
+ require 'ditty/generators/project_generator'
11
+ require 'ditty/generators/migration_generator'
12
+ require 'ditty/components/ditty'
8
13
 
9
14
  module Ditty
10
15
  class CLI < Thor
11
16
  include Thor::Actions
12
17
 
18
+ register ::Ditty::Generators::CrudGenerator, 'crud', 'crud NAME', 'Generate a CRUD endpoint'
19
+
20
+ register ::Ditty::Generators::ProjectGenerator, 'init', 'init', 'Initialize a Ditty Project'
21
+
22
+ register ::Ditty::Generators::MigrationGenerator, 'migration', 'migration NAME', 'Create a new Sequel migration'
23
+
24
+ default_task :server
25
+
13
26
  desc 'server', 'Start the Ditty server'
14
27
  require './application' if File.exist?('application.rb')
15
- Ditty::Components.tasks
28
+ ::Ditty::Components.tasks
16
29
  def server
17
30
  # Ensure the token files are present
18
31
  Rake::Task['ditty:generate_tokens'].invoke
19
32
 
20
33
  # Prep Ditty
21
- Rake::Task['ditty:prep'].invoke
34
+ Rake::Task['ditty:prep:folders'].invoke
35
+ Rake::Task['ditty:prep:migrations'].invoke
22
36
 
23
37
  # Check the migrations
24
38
  Rake::Task['ditty:migrate:check'].invoke
@@ -35,7 +49,7 @@ module Ditty
35
49
  desc 'migrate', 'Run the Ditty migrations'
36
50
  def migrate
37
51
  # Prep Ditty
38
- Rake::Task['ditty:prep'].invoke
52
+ Rake::Task['ditty:prep:migrations'].invoke
39
53
 
40
54
  # Run the migrations
41
55
  Rake::Task['ditty:migrate:up'].invoke
@@ -44,5 +58,15 @@ module Ditty
44
58
  Rake::Task['ditty:dump_schema'].invoke
45
59
  puts 'Ditty DB Schema Dumped'
46
60
  end
61
+
62
+ desc 'seed', 'Seed the predefined seeind data'
63
+ def seed
64
+ Rake::Task['ditty:seed'].invoke
65
+ end
66
+
67
+ desc 'console', 'Open a fully loaded console'
68
+ def console
69
+ Rake::Task['ditty:console'].invoke
70
+ end
47
71
  end
48
72
  end
@@ -4,10 +4,10 @@ require 'ditty'
4
4
  require 'ditty/services/settings'
5
5
 
6
6
  module Ditty
7
- class App
7
+ class Ditty
8
8
  def self.load
9
9
  controllers = File.expand_path('../controllers', __dir__)
10
- Dir.glob("#{controllers}/*.rb").each { |f| require f }
10
+ Dir.glob("#{controllers}/*.rb").sort.each { |f| require f }
11
11
 
12
12
  require 'ditty/models/user'
13
13
  require 'ditty/models/role'
@@ -29,15 +29,19 @@ module Ditty
29
29
  File.expand_path('../../../views', __dir__)
30
30
  end
31
31
 
32
+ def self.public_folder
33
+ File.expand_path('../../../public', __dir__)
34
+ end
35
+
32
36
  def self.routes
33
37
  load
34
38
  {
35
- '/' => ::Ditty::Main,
36
- '/auth' => ::Ditty::Auth,
37
- '/users' => ::Ditty::Users,
38
- '/roles' => ::Ditty::Roles,
39
- '/audit-logs' => ::Ditty::AuditLogs,
40
- '/login-traits' => ::Ditty::UserLoginTraits
39
+ '/' => ::Ditty::MainController,
40
+ '/auth' => ::Ditty::AuthController,
41
+ '/users' => ::Ditty::UsersController,
42
+ '/roles' => ::Ditty::RolesController,
43
+ '/audit-logs' => ::Ditty::AuditLogsController,
44
+ '/login-traits' => ::Ditty::UserLoginTraitsController
41
45
  }
42
46
  end
43
47
 
@@ -53,7 +57,8 @@ module Ditty
53
57
  items: [
54
58
  { order: 10, link: '/users/', text: 'Users', target: ::Ditty::User, icon: 'user' },
55
59
  { order: 20, link: '/roles/', text: 'Roles', target: ::Ditty::Role, icon: 'check-square' },
56
- { order: 30, link: '/audit-logs/', text: 'Audit Logs', target: ::Ditty::AuditLog, icon: 'history' }
60
+ { order: 30, link: '/audit-logs/', text: 'Audit Logs', target: ::Ditty::AuditLog, icon: 'history' },
61
+ { order: 40, link: '/login-traits/', text: 'User Login Traits', target: ::Ditty::UserLoginTrait, icon: 'list' }
57
62
  ]
58
63
  }
59
64
  ]
@@ -63,18 +68,18 @@ module Ditty
63
68
  proc do
64
69
  load
65
70
 
66
- ::Ditty::Role.find_or_create(name: 'super_admin')
67
- ::Ditty::Role.find_or_create(name: 'admin')
68
- ::Ditty::Role.find_or_create(name: 'user')
71
+ sa = ::Ditty::Role.find_or_create(name: 'super_admin')
72
+ admin = ::Ditty::Role.find_or_create(name: 'admin') { |e| e.parent = sa }
73
+ ::Ditty::Role.find_or_create(name: 'user') { |e| e.parent = admin }
69
74
  end
70
75
  end
71
76
 
72
77
  def self.tasks
73
78
  Kernel.load 'ditty/tasks/ditty.rake'
74
- auth_settings = Ditty::Services::Settings[:authentication] || {}
79
+ auth_settings = ::Ditty::Services::Settings[:authentication] || {}
75
80
  Kernel.load 'ditty/tasks/omniauth-ldap.rake' if auth_settings.key?(:ldap)
76
81
  end
77
82
  end
78
83
  end
79
84
 
80
- Ditty::Components.register_component(:app, Ditty::App)
85
+ Ditty::Components.register_component(:ditty, Ditty::Ditty)
@@ -17,13 +17,14 @@ require 'rack/contrib'
17
17
  require 'rack/csrf'
18
18
 
19
19
  module Ditty
20
- class Application < Sinatra::Base
20
+ class ApplicationController < Sinatra::Base
21
21
  include ActiveSupport::Inflector
22
22
 
23
23
  set :root, ENV['APP_ROOT'] || ::File.expand_path(::File.dirname(__FILE__) + '/../../../')
24
24
  set :map_path, nil
25
25
  set :view_location, nil
26
26
  set :view_folder, nil
27
+ set :base_path, nil
27
28
  set :model_class, nil
28
29
  set :raise_sinatra_param_exceptions, true
29
30
  set track_actions: false
@@ -42,7 +43,7 @@ module Ditty
42
43
 
43
44
  helpers do
44
45
  def logger
45
- Ditty::Services::Logger.instance
46
+ ::Ditty::Services::Logger
46
47
  end
47
48
 
48
49
  def base_path
@@ -51,9 +52,9 @@ module Ditty
51
52
 
52
53
  def view_location
53
54
  return settings.view_location if settings.view_location
54
- return underscore(pluralize(demodulize(settings.model_class))) if settings.model_class
55
55
 
56
- underscore(demodulize(self.class))
56
+ loc = demodulize(settings.model_class || self.class)
57
+ pluralize(underscore(loc.gsub(/Controller\Z/, '')))
57
58
  end
58
59
 
59
60
  def browser
@@ -61,24 +62,26 @@ module Ditty
61
62
  end
62
63
 
63
64
  def config(name, default = '')
64
- Ditty::Services::Settings[name] || default
65
+ ::Ditty::Services::Settings[name] || default
65
66
  end
66
67
  end
67
68
 
68
69
  def view_folders
69
70
  folders = ['./views']
70
71
  folders << settings.view_folder if settings.view_folder
71
- folders << Ditty::App.view_folder
72
+ folders << ::Ditty::Ditty.view_folder
72
73
  end
73
74
 
74
75
  def find_template(views, name, engine, &block)
75
76
  # Backwards compatability
76
- return super(views, name, engine, &block) if settings.view_folder.nil? && self.class.name.split('::').first != 'Ditty'
77
+ if settings.view_folder.nil? && self.class.name.split('::').first != 'Ditty'
78
+ return super(views, name, engine, &block)
79
+ end
77
80
 
78
81
  view_folders.each do |folder|
79
82
  super(folder, name, engine, &block) # Root
80
83
  end
81
- raise Ditty::TemplateNotFoundError, "Could not find template `#{name}`"
84
+ raise ::Ditty::TemplateNotFoundError, "Could not find template `#{name}`"
82
85
  end
83
86
 
84
87
  configure :production do
@@ -92,7 +95,7 @@ module Ditty
92
95
 
93
96
  configure :production, :development do
94
97
  disable :logging
95
- use Rack::CommonLogger, Ditty::Services::Logger.instance
98
+ use Rack::CommonLogger, ::Ditty::Services::Logger
96
99
  end
97
100
 
98
101
  not_found do
@@ -102,7 +105,11 @@ module Ditty
102
105
  haml :'404', locals: { title: '4 oh 4' }, layout: layout
103
106
  end
104
107
  format.json do
105
- json code: 404, errors: ['Not Found']
108
+ if response.body.empty?
109
+ json code: 404, errors: ['Not Found']
110
+ else
111
+ [404, response.body]
112
+ end
106
113
  end
107
114
  end
108
115
  end
@@ -134,30 +141,46 @@ module Ditty
134
141
  end
135
142
  end
136
143
 
137
- error Sequel::ValidationFailed do
144
+ error ::Sinatra::Param::InvalidParameterError do
138
145
  respond_to do |format|
139
- entity = env['sinatra.error'].model
140
- errors = env['sinatra.error'].errors
141
146
  status 400
142
147
  format.html do
143
- action = entity.id ? :edit : :new
144
- haml :"#{view_location}/#{action}", locals: { entity: entity, title: heading(action) }, layout: layout
148
+ flash.now[:danger] = env['sinatra.error'].message
149
+ haml :'400', locals: { title: '4 oh oh' }, layout: layout
145
150
  end
146
151
  format.json do
147
- json code: 400, errors: errors, full_errors: errors.full_messages
152
+ json code: 400, errors: { env['sinatra.error'].param => env['sinatra.error'].message }, full_errors: [env['sinatra.error'].message]
148
153
  end
149
154
  end
150
155
  end
151
156
 
152
- error Sinatra::Param::InvalidParameterError do
157
+ error ::Sequel::NoMatchingRow do
153
158
  respond_to do |format|
159
+ status 404
160
+ format.html do
161
+ haml :'404', locals: { title: '4 oh 4' }, layout: layout
162
+ end
163
+ format.json do
164
+ if response.body.empty?
165
+ json code: 404, errors: ['Not Found']
166
+ else
167
+ [404, response.body]
168
+ end
169
+ end
170
+ end
171
+ end
172
+
173
+ error ::Sequel::ValidationFailed do
174
+ respond_to do |format|
175
+ entity = env['sinatra.error'].model
176
+ errors = env['sinatra.error'].errors
154
177
  status 400
155
178
  format.html do
156
- flash.now[:danger] = env['sinatra.error'].message
157
- haml :'400', locals: { title: '4 oh oh' }, layout: layout
179
+ action = entity.id ? :edit : :new
180
+ haml :"#{view_location}/#{action}", locals: { entity: entity, title: heading(action) }, layout: layout
158
181
  end
159
182
  format.json do
160
- json code: 400, errors: { env['sinatra.error'].param => env['sinatra.error'].message }, full_errors: [env['sinatra.error'].message]
183
+ json code: 400, errors: errors, full_errors: errors.full_messages
161
184
  end
162
185
  end
163
186
  end
@@ -177,7 +200,7 @@ module Ditty
177
200
  end
178
201
  end
179
202
 
180
- error Ditty::TemplateNotFoundError do
203
+ error ::Ditty::TemplateNotFoundError do
181
204
  # TODO: Display a better error message
182
205
  error = env['sinatra.error']
183
206
  broadcast(:application_error, error)
@@ -207,10 +230,10 @@ module Ditty
207
230
 
208
231
  before(/.*/) do
209
232
  logger.info "Running with #{self.class} - #{request.path_info}"
210
- if request.path =~ /.*\.json\Z/
233
+ if /.*\.json\Z/.match?(request.path)
211
234
  content_type :json
212
235
  request.path_info = request.path_info.gsub(/.json$/, '')
213
- elsif request.path =~ /.*\.csv\Z/
236
+ elsif /.*\.csv\Z/.match?(request.path)
214
237
  content_type :csv
215
238
  request.path_info = request.path_info.gsub(/.csv$/, '')
216
239
  elsif request.env['ACCEPT']
@@ -222,15 +245,21 @@ module Ditty
222
245
 
223
246
  after do
224
247
  return if params[:layout].nil?
248
+ return unless response.body.respond_to?(:map)
225
249
 
226
- response.body = response.body.map do |resp|
227
- document = Oga.parse_html(resp)
228
- document.css('a').each do |elm|
229
- unless (href = elm.get('href')).nil?
230
- elm.set 'href', with_layout(href)
250
+ begin
251
+ orig = response.body
252
+ response.body = response.body.map do |resp|
253
+ document = Oga.parse_html(resp)
254
+ document.css('a').each do |elm|
255
+ unless (href = elm.get('href')).nil?
256
+ elm.set 'href', with_layout(href)
257
+ end
231
258
  end
259
+ document.to_xml
232
260
  end
233
- document.to_xml
261
+ rescue StandardError => _e
262
+ orig
234
263
  end
235
264
  end
236
265
  end