eucalypt 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (160) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +3 -0
  3. data/LICENSE +21 -0
  4. data/README.md +26 -0
  5. data/Rakefile +2 -0
  6. data/bin/eucalypt +3 -0
  7. data/eucalypt.gemspec +39 -0
  8. data/lib/eucalypt/app.rb +6 -0
  9. data/lib/eucalypt/controller.rb +10 -0
  10. data/lib/eucalypt/errors.rb +109 -0
  11. data/lib/eucalypt/eucalypt-blog/helpers.rb +106 -0
  12. data/lib/eucalypt/eucalypt-blog/namespaces/blog/__base__.rb +22 -0
  13. data/lib/eucalypt/eucalypt-blog/namespaces/blog/__require__.rb +1 -0
  14. data/lib/eucalypt/eucalypt-blog/namespaces/blog/cli/blog.rb +65 -0
  15. data/lib/eucalypt/eucalypt-blog/namespaces/blog/generators/article.rb +28 -0
  16. data/lib/eucalypt/eucalypt-blog/namespaces/blog/generators/controller.rb +14 -0
  17. data/lib/eucalypt/eucalypt-blog/namespaces/blog/generators/helper.rb +12 -0
  18. data/lib/eucalypt/eucalypt-blog/namespaces/blog/generators/list.rb +74 -0
  19. data/lib/eucalypt/eucalypt-blog/namespaces/blog/generators/views.rb +20 -0
  20. data/lib/eucalypt/eucalypt-blog/namespaces/blog/templates/controller/controller.tt +33 -0
  21. data/lib/eucalypt/eucalypt-blog/namespaces/blog/templates/controller/controller_spec.tt +43 -0
  22. data/lib/eucalypt/eucalypt-blog/namespaces/blog/templates/helper/helper.tt +5 -0
  23. data/lib/eucalypt/eucalypt-blog/namespaces/blog/templates/helper/helper_spec.tt +9 -0
  24. data/lib/eucalypt/eucalypt-blog/namespaces/blog/templates/views/article.erb +1 -0
  25. data/lib/eucalypt/eucalypt-blog/namespaces/blog/templates/views/article_layout.erb +10 -0
  26. data/lib/eucalypt/eucalypt-blog/namespaces/blog/templates/views/article_md.tt +9 -0
  27. data/lib/eucalypt/eucalypt-blog/namespaces/blog/templates/views/articles.erb +1 -0
  28. data/lib/eucalypt/eucalypt-blog/namespaces/blog/templates/views/articles_layout.erb +10 -0
  29. data/lib/eucalypt/eucalypt-blog/namespaces/blog/templates/views/search.erb +1 -0
  30. data/lib/eucalypt/eucalypt-blog/namespaces/blog-article/cli/article.rb +120 -0
  31. data/lib/eucalypt/eucalypt-blog/namespaces/blog-article-edit/cli/edit-datetime.rb +113 -0
  32. data/lib/eucalypt/eucalypt-blog/namespaces/blog-article-edit/cli/edit-urltitle.rb +75 -0
  33. data/lib/eucalypt/eucalypt-core/cli/__base__.rb +11 -0
  34. data/lib/eucalypt/eucalypt-core/cli/console.rb +15 -0
  35. data/lib/eucalypt/eucalypt-core/cli/core.rb +6 -0
  36. data/lib/eucalypt/eucalypt-core/cli/help.rb +11 -0
  37. data/lib/eucalypt/eucalypt-core/cli/init.rb +71 -0
  38. data/lib/eucalypt/eucalypt-core/cli/launch.rb +33 -0
  39. data/lib/eucalypt/eucalypt-core/cli/test.rb +16 -0
  40. data/lib/eucalypt/eucalypt-core/cli/version.rb +11 -0
  41. data/lib/eucalypt/eucalypt-core/templates/Gemfile.tt +35 -0
  42. data/lib/eucalypt/eucalypt-core/templates/eucalypt/.gitignore +48 -0
  43. data/lib/eucalypt/eucalypt-core/templates/eucalypt/.travis.yml +8 -0
  44. data/lib/eucalypt/eucalypt-core/templates/eucalypt/Procfile +1 -0
  45. data/lib/eucalypt/eucalypt-core/templates/eucalypt/Rakefile +7 -0
  46. data/lib/eucalypt/eucalypt-core/templates/eucalypt/app/assets/fonts/.empty_directory +0 -0
  47. data/lib/eucalypt/eucalypt-core/templates/eucalypt/app/assets/images/.empty_directory +0 -0
  48. data/lib/eucalypt/eucalypt-core/templates/eucalypt/app/assets/scripts/application.js +17 -0
  49. data/lib/eucalypt/eucalypt-core/templates/eucalypt/app/assets/stylesheets/__partials__.scss +16 -0
  50. data/lib/eucalypt/eucalypt-core/templates/eucalypt/app/assets/stylesheets/application.scss +17 -0
  51. data/lib/eucalypt/eucalypt-core/templates/eucalypt/app/assets/stylesheets/partials/_mixins.scss +54 -0
  52. data/lib/eucalypt/eucalypt-core/templates/eucalypt/app/controllers/application_controller.rb +7 -0
  53. data/lib/eucalypt/eucalypt-core/templates/eucalypt/app/helpers/application_helper.rb +3 -0
  54. data/lib/eucalypt/eucalypt-core/templates/eucalypt/app/models/.empty_directory +0 -0
  55. data/lib/eucalypt/eucalypt-core/templates/eucalypt/app/static/.empty_directory +0 -0
  56. data/lib/eucalypt/eucalypt-core/templates/eucalypt/app/static/readme.yml +34 -0
  57. data/lib/eucalypt/eucalypt-core/templates/eucalypt/app/views/index.erb +0 -0
  58. data/lib/eucalypt/eucalypt-core/templates/eucalypt/app/views/layouts/main.erb +9 -0
  59. data/lib/eucalypt/eucalypt-core/templates/eucalypt/app/views/partials/.empty_directory +0 -0
  60. data/lib/eucalypt/eucalypt-core/templates/eucalypt/app.rb +42 -0
  61. data/lib/eucalypt/eucalypt-core/templates/eucalypt/config/active_record.rb +6 -0
  62. data/lib/eucalypt/eucalypt-core/templates/eucalypt/config/asset_pipeline.rb +15 -0
  63. data/lib/eucalypt/eucalypt-core/templates/eucalypt/config/database.yml +16 -0
  64. data/lib/eucalypt/eucalypt-core/templates/eucalypt/config/initializers/.empty_directory +0 -0
  65. data/lib/eucalypt/eucalypt-core/templates/eucalypt/config/logging.rb +27 -0
  66. data/lib/eucalypt/eucalypt-core/templates/eucalypt/config/manifest.rb +15 -0
  67. data/lib/eucalypt/eucalypt-core/templates/eucalypt/config.ru +10 -0
  68. data/lib/eucalypt/eucalypt-core/templates/eucalypt/log/.empty_directory +0 -0
  69. data/lib/eucalypt/eucalypt-core/templates/eucalypt/spec/controllers/application_controller_spec.rb +9 -0
  70. data/lib/eucalypt/eucalypt-core/templates/eucalypt/spec/helpers/application_helper_spec.rb +9 -0
  71. data/lib/eucalypt/eucalypt-core/templates/eucalypt/spec/models/.empty_directory +0 -0
  72. data/lib/eucalypt/eucalypt-core/templates/eucalypt/spec/spec_helper.rb +18 -0
  73. data/lib/eucalypt/eucalypt-destroy/helpers.rb +77 -0
  74. data/lib/eucalypt/eucalypt-destroy/namespaces/destroy/cli/destroy-controller.rb +16 -0
  75. data/lib/eucalypt/eucalypt-destroy/namespaces/destroy/cli/destroy-helper.rb +16 -0
  76. data/lib/eucalypt/eucalypt-destroy/namespaces/destroy/cli/destroy-model.rb +16 -0
  77. data/lib/eucalypt/eucalypt-destroy/namespaces/destroy/cli/destroy-scaffold.rb +63 -0
  78. data/lib/eucalypt/eucalypt-destroy/namespaces/destroy/cli/destroy.rb +21 -0
  79. data/lib/eucalypt/eucalypt-generate/.gitkeep +0 -0
  80. data/lib/eucalypt/eucalypt-generate/namespaces/generate/cli/generate-scaffold.rb +62 -0
  81. data/lib/eucalypt/eucalypt-generate/namespaces/generate/cli/generate.rb +24 -0
  82. data/lib/eucalypt/eucalypt-generate/namespaces/generate-controller/cli/generate-controller.rb +29 -0
  83. data/lib/eucalypt/eucalypt-generate/namespaces/generate-controller/generators/controller.rb +45 -0
  84. data/lib/eucalypt/eucalypt-generate/namespaces/generate-controller/templates/controller/controller.tt +3 -0
  85. data/lib/eucalypt/eucalypt-generate/namespaces/generate-controller/templates/controller/policy_rest_controller.tt +71 -0
  86. data/lib/eucalypt/eucalypt-generate/namespaces/generate-controller/templates/controller/rest_controller.tt +28 -0
  87. data/lib/eucalypt/eucalypt-generate/namespaces/generate-controller/templates/controller_spec.tt +9 -0
  88. data/lib/eucalypt/eucalypt-generate/namespaces/generate-helper/cli/generate-helper.rb +23 -0
  89. data/lib/eucalypt/eucalypt-generate/namespaces/generate-helper/generators/helper.rb +24 -0
  90. data/lib/eucalypt/eucalypt-generate/namespaces/generate-helper/templates/helper.tt +3 -0
  91. data/lib/eucalypt/eucalypt-generate/namespaces/generate-helper/templates/helper_spec.tt +9 -0
  92. data/lib/eucalypt/eucalypt-generate/namespaces/generate-model/cli/generate-model.rb +26 -0
  93. data/lib/eucalypt/eucalypt-generate/namespaces/generate-model/generators/model.rb +25 -0
  94. data/lib/eucalypt/eucalypt-generate/namespaces/generate-model/templates/model.tt +3 -0
  95. data/lib/eucalypt/eucalypt-generate/namespaces/generate-model/templates/model_spec.tt +8 -0
  96. data/lib/eucalypt/eucalypt-migration/helpers.rb +93 -0
  97. data/lib/eucalypt/eucalypt-migration/migration_base.tt +4 -0
  98. data/lib/eucalypt/eucalypt-migration/namespaces/migration/cli/migration.rb +39 -0
  99. data/lib/eucalypt/eucalypt-migration/namespaces/migration-add/cli/add-column.rb +25 -0
  100. data/lib/eucalypt/eucalypt-migration/namespaces/migration-add/cli/add-index.rb +25 -0
  101. data/lib/eucalypt/eucalypt-migration/namespaces/migration-add/cli/add.rb +18 -0
  102. data/lib/eucalypt/eucalypt-migration/namespaces/migration-add/generators/column.rb +46 -0
  103. data/lib/eucalypt/eucalypt-migration/namespaces/migration-add/generators/index.rb +52 -0
  104. data/lib/eucalypt/eucalypt-migration/namespaces/migration-blank/cli/blank.rb +22 -0
  105. data/lib/eucalypt/eucalypt-migration/namespaces/migration-blank/generators/blank.rb +28 -0
  106. data/lib/eucalypt/eucalypt-migration/namespaces/migration-change/cli/change-column.rb +23 -0
  107. data/lib/eucalypt/eucalypt-migration/namespaces/migration-change/cli/change.rb +17 -0
  108. data/lib/eucalypt/eucalypt-migration/namespaces/migration-change/generators/column.rb +46 -0
  109. data/lib/eucalypt/eucalypt-migration/namespaces/migration-create/cli/create-table.rb +25 -0
  110. data/lib/eucalypt/eucalypt-migration/namespaces/migration-create/cli/create.rb +17 -0
  111. data/lib/eucalypt/eucalypt-migration/namespaces/migration-create/generators/table.rb +53 -0
  112. data/lib/eucalypt/eucalypt-migration/namespaces/migration-drop/cli/drop-column.rb +22 -0
  113. data/lib/eucalypt/eucalypt-migration/namespaces/migration-drop/cli/drop-index.rb +23 -0
  114. data/lib/eucalypt/eucalypt-migration/namespaces/migration-drop/cli/drop-table.rb +22 -0
  115. data/lib/eucalypt/eucalypt-migration/namespaces/migration-drop/cli/drop.rb +19 -0
  116. data/lib/eucalypt/eucalypt-migration/namespaces/migration-drop/generators/column.rb +38 -0
  117. data/lib/eucalypt/eucalypt-migration/namespaces/migration-drop/generators/index.rb +48 -0
  118. data/lib/eucalypt/eucalypt-migration/namespaces/migration-drop/generators/table.rb +37 -0
  119. data/lib/eucalypt/eucalypt-migration/namespaces/migration-rename/cli/rename-column.rb +22 -0
  120. data/lib/eucalypt/eucalypt-migration/namespaces/migration-rename/cli/rename-index.rb +22 -0
  121. data/lib/eucalypt/eucalypt-migration/namespaces/migration-rename/cli/rename-table.rb +24 -0
  122. data/lib/eucalypt/eucalypt-migration/namespaces/migration-rename/cli/rename.rb +19 -0
  123. data/lib/eucalypt/eucalypt-migration/namespaces/migration-rename/generators/column.rb +39 -0
  124. data/lib/eucalypt/eucalypt-migration/namespaces/migration-rename/generators/index.rb +39 -0
  125. data/lib/eucalypt/eucalypt-migration/namespaces/migration-rename/generators/table.rb +38 -0
  126. data/lib/eucalypt/eucalypt-security/helpers.rb +22 -0
  127. data/lib/eucalypt/eucalypt-security/namespaces/security/cli/security.rb +31 -0
  128. data/lib/eucalypt/eucalypt-security/namespaces/security-policy/cli/security-policy.rb +91 -0
  129. data/lib/eucalypt/eucalypt-security/namespaces/security-policy/generators/policy.rb +31 -0
  130. data/lib/eucalypt/eucalypt-security/namespaces/security-policy/templates/create_policy_roles_migration.tt +11 -0
  131. data/lib/eucalypt/eucalypt-security/namespaces/security-policy/templates/policy.tt +16 -0
  132. data/lib/eucalypt/eucalypt-security/namespaces/security-policy-permission/cli/security-policy-permission.rb +62 -0
  133. data/lib/eucalypt/eucalypt-security/namespaces/security-policy-permission/generators/policy-permission.rb +28 -0
  134. data/lib/eucalypt/eucalypt-security/namespaces/security-policy-permission/templates/add_permission_to_policy_migration.tt +5 -0
  135. data/lib/eucalypt/eucalypt-security/namespaces/security-policy-role/cli/security-policy-role.rb +66 -0
  136. data/lib/eucalypt/eucalypt-security/namespaces/security-pundit/cli/security-pundit.rb +79 -0
  137. data/lib/eucalypt/eucalypt-security/namespaces/security-pundit/generators/role.rb +24 -0
  138. data/lib/eucalypt/eucalypt-security/namespaces/security-pundit/templates/create_roles_migration.tt +7 -0
  139. data/lib/eucalypt/eucalypt-security/namespaces/security-pundit/templates/pundit.tt +4 -0
  140. data/lib/eucalypt/eucalypt-security/namespaces/security-warden/cli/security-warden.rb +61 -0
  141. data/lib/eucalypt/eucalypt-security/namespaces/security-warden/generators/auth_controller.rb +34 -0
  142. data/lib/eucalypt/eucalypt-security/namespaces/security-warden/generators/user.rb +37 -0
  143. data/lib/eucalypt/eucalypt-security/namespaces/security-warden/templates/auth_controller.tt +25 -0
  144. data/lib/eucalypt/eucalypt-security/namespaces/security-warden/templates/auth_login.tt +1 -0
  145. data/lib/eucalypt/eucalypt-security/namespaces/security-warden/templates/create_users_table_migration.tt +9 -0
  146. data/lib/eucalypt/eucalypt-security/namespaces/security-warden/templates/user.tt +16 -0
  147. data/lib/eucalypt/eucalypt-security/namespaces/security-warden/templates/warden.tt +35 -0
  148. data/lib/eucalypt/eucalypt-security/namespaces/security-warden/user_confirm.rb +38 -0
  149. data/lib/eucalypt/helpers/colorize.rb +27 -0
  150. data/lib/eucalypt/helpers/gemfile.rb +48 -0
  151. data/lib/eucalypt/helpers/inflect.rb +79 -0
  152. data/lib/eucalypt/helpers/messages.rb +31 -0
  153. data/lib/eucalypt/helpers/migration.rb +85 -0
  154. data/lib/eucalypt/helpers/numeric.rb +10 -0
  155. data/lib/eucalypt/helpers.rb +6 -0
  156. data/lib/eucalypt/list.rb +39 -0
  157. data/lib/eucalypt/static.rb +48 -0
  158. data/lib/eucalypt/version.rb +3 -0
  159. data/lib/eucalypt.rb +19 -0
  160. metadata +373 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: aa6a5ff7a9dcd9363c00239a5f3c4f061cf4462c619cc8b59f1cdf406cd876b3
4
+ data.tar.gz: 5b40cd192caec208c295bbe054b4bded5bbb87d4c0a8fe50feeb94a16159edfc
5
+ SHA512:
6
+ metadata.gz: 7d0814b65d0d6c769e0d4f104066c5aeee5b3be0b4f0c0da18955b38938e951ddf71cf11918e6adca2c33a169cf8ede27a92f9b55b3bd784e5ad06340e5a8bce
7
+ data.tar.gz: 2445d94f7f54fb716c06220d429b94a895b352172ddb85ce91abc163b23c8dad51bf1a8de31410daf3863d0a468764c3846afc6b12cf1dce92e44829dc36a9ff
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018 Edwin Onuonga
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,26 @@
1
+ [![Ruby Version](https://img.shields.io/badge/ruby-~%3E%202.5-red.svg)](https://github.com/eonu/eucalypt/blob/0c509a4e22fd97ec52b6f638af21de783f3aafc8/eucalypt.gemspec#L19)
2
+ [![Gem](https://img.shields.io/gem/v/eucalypt.svg)](https://rubygems.org/gems/eucalypt)
3
+ [![Build Status](https://travis-ci.org/eonu/eucalypt.svg?branch=master)]
4
+ [![License](https://img.shields.io/github/license/eonu/eucalypt.svg)]
5
+
6
+ # Eucalypt
7
+
8
+ Micro-framework and CLI for the generation and maintenance of structured Sinatra web applications.
9
+
10
+ ## Installation
11
+
12
+ To install the CLI, run:
13
+
14
+ ```bash
15
+ $ gem install eucalypt
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ Initialize a new application with:
21
+
22
+ ```bash
23
+ $ eucalypt init my-new-app
24
+ ```
25
+
26
+ And you're ready to go!
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
data/bin/eucalypt ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require 'eucalypt'
3
+ Eucalypt::CLI.start
data/eucalypt.gemspec ADDED
@@ -0,0 +1,39 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "eucalypt/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "eucalypt"
7
+ spec.version = Eucalypt::VERSION
8
+ spec.authors = ["Edwin Onuonga"]
9
+ spec.email = ["edwinonuonga@gmail.com"]
10
+
11
+ spec.summary = %q{Micro-framework and CLI for the generation and maintenance of structured Sinatra web applications.}
12
+ spec.homepage = "https://eucalypt.gitbook.io/eucalypt/"
13
+ spec.license = "MIT"
14
+ spec.files = Dir.glob('lib/**/*', File::FNM_DOTMATCH) + %w[Gemfile LICENSE README.md Rakefile eucalypt.gemspec bin/eucalypt]
15
+ spec.bindir = "bin"
16
+ spec.executables = spec.files.grep(%r{^bin/}) {|f| File.basename(f)}
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.required_ruby_version = "~> 2.5"
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.16"
22
+ spec.add_development_dependency "rake", "~> 12.3"
23
+ spec.add_development_dependency "rspec", "~> 3.7"
24
+ spec.add_development_dependency "regexp-examples", "~> 1.4"
25
+ spec.add_development_dependency "colorize", "~> 0.8"
26
+
27
+ spec.add_runtime_dependency "string-builder", "~> 2.3"
28
+ spec.add_runtime_dependency "activesupport", "~> 5.2"
29
+ spec.add_runtime_dependency "activerecord", "~> 5.2"
30
+ spec.add_runtime_dependency "front_matter_parser", "0.2.0"
31
+ spec.add_runtime_dependency "thor", "~> 0.20"
32
+ spec.add_runtime_dependency "sinatra", "~> 2.0"
33
+ spec.add_runtime_dependency "rerun", "~> 0.13"
34
+
35
+ spec.metadata = {
36
+ # "documentation_uri" => "https://eucalypt.gitbook.io/eucalypt/",
37
+ "source_code_uri" => "https://github.com/eucalypt/eucalypt/"
38
+ }
39
+ end
@@ -0,0 +1,6 @@
1
+ module Eucalypt
2
+ APP_FILE = 'Gumfile'.freeze
3
+ def self.app?(directory)
4
+ File.exist? File.join(directory, APP_FILE)
5
+ end
6
+ end
@@ -0,0 +1,10 @@
1
+ require 'sinatra'
2
+ class ApplicationController < Sinatra::Base; end
3
+ module Eucalypt
4
+ def self.Controller(route:)
5
+ name = File.basename(caller[0][/[^:]+/],'.*').camelize
6
+ Object.const_set name, Class.new(::ApplicationController)
7
+ name.constantize.instance_eval %{def router() "#{route}" end}
8
+ ::ApplicationController
9
+ end
10
+ end
@@ -0,0 +1,109 @@
1
+ require 'eucalypt/app'
2
+ require 'eucalypt/helpers'
3
+ require 'string/builder'
4
+
5
+ module Eucalypt
6
+ module Error
7
+ include Eucalypt::Helpers
8
+ include Eucalypt::Helpers::Messages
9
+ using String::Builder
10
+ using Colorize
11
+
12
+ class << self
13
+ include Eucalypt::Helpers::Messages
14
+ def wrong_directory
15
+ puts
16
+ Out.error "Couldn't find #{Eucalypt::APP_FILE.colorize(:bold)} in current directory."
17
+ puts
18
+ Out.info 'Try:'
19
+ puts " - Changing the current working directory to your application's root directory."
20
+ puts " - Creating a new application with `#{'eucalypt init'.colorize(:bold)}`."
21
+ puts " - Creating a #{Eucalypt::APP_FILE.colorize(:bold)} if you deleted it."
22
+ end
23
+
24
+ def found_app_file
25
+ Out.warning "Found #{Eucalypt::APP_FILE.colorize(:bold)} in the current directory."
26
+ puts
27
+ Out.info
28
+ puts " - The current directory might already be a Eucalypt application."
29
+ puts " - Proceeding with the initialization will create a new nested application."
30
+ puts " - This shouldn't be a problem, but is it really what you intended?"
31
+ puts
32
+ end
33
+
34
+ def no_articles
35
+ Out.error "Couldn't find any blog articles"
36
+ end
37
+
38
+ def delete_article_warning
39
+ Out.warning 'Deleting an article will delete both the markdown file and all assets!'
40
+ end
41
+
42
+ def no_mvc(mvc_file)
43
+ Out.error "Couldn't find any #{mvc_file}s"
44
+ end
45
+
46
+ def no_scaffolds
47
+ Out.error "Couldn't find any scaffolds."
48
+ end
49
+
50
+ def no_gems(gems, command)
51
+ Out.error "Couldn't find gems #{gems} in Gemfile."
52
+ puts
53
+ Out.info
54
+ puts " - Ensure you have run the setup command `#{command.colorize(:bold)}`."
55
+ end
56
+
57
+ def no_user_model
58
+ Out.error "Couldn't find a user model."
59
+ puts
60
+ Out.info
61
+ command = 'eucalypt security warden setup'
62
+ puts " - Ensure you have run the setup command `#{command.colorize(:bold)}`."
63
+ end
64
+
65
+ def no_role_model
66
+ Out.error "Couldn't find a role model."
67
+ puts
68
+ Out.info
69
+ command = 'eucalypt security pundit setup'
70
+ puts " - Ensure you have run the setup command `#{command.colorize(:bold)}`."
71
+ end
72
+
73
+ def no_policy(policy_name)
74
+ Out.error "Couldn't find a #{policy_name} role model or policy file."
75
+ puts
76
+ Out.info
77
+ command = "eucalypt security policy g #{policy_name}"
78
+ puts " - Ensure you have run the setup command `#{command.colorize(:bold)}`."
79
+ end
80
+
81
+ def invalid_columns(invalid_declarations, invalid_types)
82
+ puts if invalid_declarations.any? || invalid_types.any?
83
+ if invalid_declarations.any?
84
+ Out.error "Invalid column declaration(s): #{invalid_declarations.inspect}"
85
+ Out.info "Column declarations should match the regex: #{Eucalypt::Helpers::Migration::Validation::DECLARATION_REGEX.inspect}"
86
+ puts " - Examples: name:string, price:decimal, elo:primary_key"
87
+ end
88
+ if invalid_types.any?
89
+ output = String.build "Invalid column type(s): " do |s|
90
+ invalid_types.each_with_index do |obj, i|
91
+ type, column = obj[:type], obj[:column]
92
+ s << "#{column}:#{type.colorize(:bold)}"
93
+ s << ', ' unless i == invalid_types.size-1
94
+ end
95
+ end
96
+ puts if invalid_declarations.any? && invalid_types.any?
97
+ Out.error output
98
+ Out.info "To list all permitted column types, run the command `#{"eucalypt migration types".colorize(:bold)}`"
99
+ end
100
+ end
101
+
102
+ def invalid_type(type)
103
+ puts
104
+ Out.error "Invalid column type: #{type.colorize(:bold)}"
105
+ Out.info "To list all permitted column types, run the command `#{"eucalypt migration types".colorize(:bold)}`"
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,106 @@
1
+ require 'thor'
2
+ module Eucalypt
3
+ class Blog < Thor
4
+ module Helpers
5
+
6
+ module Array::DateSort
7
+ refine Array.singleton_class do
8
+ def date_sorter(order, obj)
9
+ obj.sort! do |x1, x2|
10
+ if order == :ascending
11
+ x1[:datetime] <=> x2[:datetime]
12
+ else
13
+ x2[:datetime] <=> x1[:datetime]
14
+ end
15
+ end
16
+ end
17
+ end
18
+ refine Array do
19
+ def sort_by_date!(order: :descending)
20
+ obj = self.map!{|x|x[:datetime] = DateTime.strptime(x[:time], "%Y-%m-%d %H:%M:%S"); x}
21
+ Array.date_sorter(order, obj)
22
+ end
23
+ def sort_by_date(order: :descending)
24
+ obj = self.map{|x|x[:datetime] = DateTime.strptime(x[:time], "%Y-%m-%d %H:%M:%S"); x}
25
+ Array.date_sorter(order, obj)
26
+ end
27
+ end
28
+ end
29
+
30
+ class Blog
31
+ class << self
32
+ def articles=(val) @@articles = val end
33
+ def articles() @@articles end
34
+ def all() @@articles.map{|md|FrontMatterParser::Parser.parse_file(md).front_matter.symbolize_keys} end
35
+ def search(query) all.select{|post|post[:tags].any?{|tag|tag.include?(query)}} end
36
+ end
37
+
38
+ class Article
39
+ def initialize(md) @parsed = FrontMatterParser::Parser.parse_file(md) end
40
+ def front_matter() @parsed.front_matter.symbolize_keys end
41
+ def content() @parsed.content end
42
+ def route() "/#{front_matter[:time].split(' ').first.gsub(?-,?/)}/#{front_matter[:urltitle]}" end
43
+ def asset(file) File.join(front_matter[:assetpath].sub('/assets',''), file) end
44
+ end
45
+ end
46
+
47
+ class << self
48
+ private
49
+
50
+ def construct_date_regex(date)
51
+ y = date[:year]
52
+ m = date[:month]
53
+ d = date[:day]
54
+ return nil unless y || m || d
55
+ return /#{y}\-#{m}\-#{d}/ if y && m && d
56
+ return /#{y}\-#{m}\-[0-9][0-9]/ if y && m && !d
57
+ return /#{y}\-[0-9][0-9]\-#{d}/ if y && !m && d
58
+ return /[0-9]*\-#{m}\-#{d}/ if !y && m && d
59
+ return /#{y}\-[0-9][0-9]\-[0-9][0-9]/ if y && !m && !d
60
+ return /[0-9]*\-#{m}\-[0-9][0-9]/ if !y && m && !d
61
+ return /[0-9]*\-[0-9][0-9]\-#{d}/ if !y && !m && d
62
+ end
63
+
64
+ def clean_directory(base)
65
+ Dir.chdir base do
66
+ Dir[?*].each do |year|
67
+ Dir.chdir year do
68
+ Dir[?*].each do |month|
69
+ Dir.chdir month do
70
+ Dir[?*].each do |day|
71
+ FileUtils.rm_rf day if Dir.empty? day
72
+ end
73
+ end
74
+ FileUtils.rm_rf month if Dir.empty? month
75
+ end
76
+ end
77
+ FileUtils.rm_rf year if Dir.empty? year
78
+ end
79
+ end
80
+ end
81
+
82
+ def build_article_hash(articles, article_base)
83
+ articles_hash = Hash.new
84
+ articles.each_with_index do |article,i|
85
+ index_key = (i+1).to_s.to_sym
86
+ articles_hash[index_key] = {}
87
+ articles_hash[index_key][:path] = article
88
+ articles_hash[index_key][:markdown] = article.split(article_base.gsub(/\/$/,'')<<?/).last
89
+ articles_hash[index_key][:identifier] = articles_hash[index_key][:markdown].rpartition(?.).first
90
+ articles_hash[index_key][:base_name] = File.basename articles_hash[index_key][:markdown]
91
+ articles_hash[index_key][:date] = articles_hash[index_key][:identifier].rpartition(?/).first
92
+ articles_hash[index_key][:front_matter] = FrontMatterParser::Parser.parse_file(
93
+ articles_hash[index_key][:path]
94
+ ).front_matter
95
+ title = articles_hash[index_key][:front_matter]['title']
96
+ puts "\e[1m#{index_key}\e[0m: #{articles_hash[index_key][:identifier]}"
97
+ puts "#{' '*(index_key.to_s.length+2)}#{title}" if title
98
+ puts
99
+ end
100
+ articles_hash
101
+ end
102
+ end
103
+
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,22 @@
1
+ require 'thor'
2
+ require 'front_matter_parser'
3
+ require 'string/builder'
4
+ require 'active_support'
5
+ require 'active_support/core_ext'
6
+
7
+ require 'eucalypt/helpers'
8
+ require 'eucalypt/eucalypt-blog/helpers'
9
+
10
+ module Eucalypt
11
+ module Generators
12
+ class Blog < Thor::Group
13
+ include Thor::Actions
14
+ include Eucalypt::Helpers
15
+ include Eucalypt::Blog::Helpers
16
+
17
+ def self.source_root
18
+ File.join __dir__, 'templates'
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1 @@
1
+ Dir[File.join __dir__, 'generators', '*.rb'].each{|file| require file}
@@ -0,0 +1,65 @@
1
+ require 'eucalypt/errors'
2
+ require 'eucalypt/helpers'
3
+ require 'eucalypt/eucalypt-blog/namespaces/blog/__require__'
4
+ require 'eucalypt/eucalypt-blog/namespaces/blog-article/cli/article'
5
+
6
+ module Eucalypt
7
+ class Blog < Thor
8
+ include Thor::Actions
9
+ include Eucalypt::Helpers
10
+ include Eucalypt::Helpers::Messages
11
+ include Eucalypt::Helpers::Gemfile
12
+ using Colorize
13
+
14
+ method_option :route, type: :string, aliases: '-r', default: 'blog', desc: "The route at which the blog lies"
15
+ desc "setup", "Sets up the blog-aware environment".colorize(:grey)
16
+ def setup
17
+ directory = File.expand_path('.')
18
+ if Eucalypt.app? directory
19
+ Out.setup 'Setting up blog environment...'
20
+
21
+ gemfile_add(
22
+ 'Markdown and YAML front-matter parsing',
23
+ {front_matter_parser: '0.2.0', rdiscount: '~> 2.2'},
24
+ directory
25
+ )
26
+
27
+ generator = Eucalypt::Generators::Blog.new
28
+ generator.destination_root = directory
29
+ generator.helper
30
+ generator.controller(route: options[:route])
31
+ generator.views
32
+
33
+ asset_pipeline_file = File.join(directory, 'config', 'asset_pipeline.rb')
34
+
35
+ File.open(asset_pipeline_file) do |f|
36
+ return if f.read.include? "environment.append_path Eucalypt.path 'app', 'assets', 'blog'"
37
+ end
38
+
39
+ insert_into_file(
40
+ asset_pipeline_file,
41
+ "\tenvironment.append_path Eucalypt.path 'app', 'assets', 'blog'\n",
42
+ after: "set :environment, Sprockets::Environment.new\n"
43
+ )
44
+ else
45
+ Eucalypt::Error.wrong_directory
46
+ end
47
+ end
48
+
49
+ class << self
50
+ require 'eucalypt/list'
51
+ include Eucalypt::List
52
+ def banner(task, namespace = false, subcommand = true)
53
+ basename + ' ' + task.formatted_usage(self, true, subcommand).split(':').join(' ')
54
+ end
55
+ end
56
+
57
+ register(Eucalypt::BlogArticle, 'article', 'article [COMMAND]', 'Create, edit and destroy blog articles'.colorize(:grey))
58
+ end
59
+
60
+ class CLI < Thor
61
+ include Eucalypt::Helpers
62
+ using Colorize
63
+ register(Blog, 'blog', 'blog [COMMAND]', 'Manage static blog environment'.colorize(:grey))
64
+ end
65
+ end
@@ -0,0 +1,28 @@
1
+ require 'eucalypt/eucalypt-blog/namespaces/blog/__base__'
2
+
3
+ module Eucalypt
4
+ module Generators
5
+ class Blog < Thor::Group
6
+ def article(urltitle:)
7
+ urltitle = Inflect.route(urltitle)
8
+
9
+ dt = Hash.new
10
+ dt[:full] = Time.now.strftime("%Y-%m-%d %H:%M:%S")
11
+ dt[:date] = dt[:full].split(' ').first
12
+
13
+ # Assets path generation
14
+ asset_base = File.join 'app', 'assets', 'blog'
15
+ asset_path = File.join asset_base, dt[:date].gsub(?-,?/), urltitle
16
+
17
+ empty_directory(asset_path)
18
+
19
+ # Markdown file and path generation
20
+ article_base = File.join 'app', 'views', 'blog', 'markdown'
21
+ article_path = File.join article_base, dt[:date].gsub(?-,?/), "#{urltitle}.md"
22
+
23
+ config = {datetime: dt[:full], date: dt[:date], urltitle: urltitle}
24
+ template File.join('views', 'article_md.tt'), article_path, config
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,14 @@
1
+ require 'eucalypt/eucalypt-blog/namespaces/blog/__base__'
2
+
3
+ module Eucalypt
4
+ module Generators
5
+ class Blog < Thor::Group
6
+ def controller(route:)
7
+ route = "/#{Inflect.route(route)}"
8
+ config = {route: route}
9
+ template File.join('controller','controller.tt'), File.join('app','controllers','blog_controller.rb'), config
10
+ template File.join('controller','controller_spec.tt'), File.join('spec','controllers','blog_controller_spec.rb')
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ require 'eucalypt/eucalypt-blog/namespaces/blog/__base__'
2
+
3
+ module Eucalypt
4
+ module Generators
5
+ class Blog < Thor::Group
6
+ def helper
7
+ template File.join('helper','helper.tt'), File.join('app','helpers','blog_helper.rb')
8
+ template File.join('helper','helper_spec.tt'), File.join('spec','helpers','blog_helper_spec.rb')
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,74 @@
1
+ require 'eucalypt/helpers'
2
+ require 'eucalypt/eucalypt-blog/namespaces/blog/__base__'
3
+
4
+ module Eucalypt
5
+ module Generators
6
+ class Blog < Thor::Group
7
+ include Eucalypt::Helpers
8
+ using Array::DateSort
9
+ using String::Builder
10
+ using Colorize
11
+
12
+ def list(tag, order, date)
13
+ chars = {corner: ?+, vertical: ?║, horizontal: ?═}
14
+
15
+ puts
16
+
17
+ files = Dir.glob(File.join(self.destination_root,"app/views/blog/markdown/**/*.md"))
18
+ if files.empty?
19
+ puts "0 article(s) found."
20
+ return
21
+ end
22
+
23
+ date_regex = Eucalypt::Blog::Helpers.send :construct_date_regex, date
24
+
25
+ metadata = files.map{|md|FrontMatterParser::Parser.parse_file(md).front_matter.symbolize_keys}
26
+ metadata.select!{|post|post[:tags].any?{|t|t.include?(tag)}} unless tag.empty?
27
+ metadata.select!{|post|date_regex.match? post[:time].split.first} if date_regex
28
+ metadata.sort_by_date!(order: order)
29
+
30
+ number = metadata.length
31
+ if number == 0
32
+ puts "0 article(s) found.\n"
33
+ return
34
+ else
35
+ puts "#{metadata.length} article(s) found.\n"
36
+ end
37
+
38
+ longest = 0
39
+ metadata.each do |article|
40
+ article.each do |k,v|
41
+ next if %i[desc datetime].include? k
42
+ str = "#{k}: #{v}"
43
+ longest = str.length if longest < str.length
44
+ end
45
+ end
46
+
47
+ output = String.build "\n" do |s|
48
+ s << (chars[:corner]+chars[:horizontal]*(longest+2)+chars[:corner]+"\n")
49
+ metadata.each do |article|
50
+ article.each do |k,v|
51
+ next if k == :datetime
52
+ str = "#{k}: #{v}"
53
+ if k == :desc
54
+ value = v.to_s
55
+ rel = longest-(k.length+5) # 5 is from ": " and "..."
56
+ unless str.length <= longest
57
+ str = "#{k}: #{value.length > rel ? "#{value[0...rel]}..." : value}"
58
+ end
59
+ end
60
+ len = str.ljust(longest,' ').length-str.length
61
+ s << "#{chars[:vertical]} "
62
+ s << "#{k.to_s.colorize(:magenta)}: #{str[(k.to_s.length+2)..-1]}"
63
+ s << ' '*len
64
+ s << " #{chars[:vertical]}\n"
65
+ end
66
+ s << (chars[:corner]+chars[:horizontal]*(longest+2)+chars[:corner]+"\n")
67
+ end
68
+ end
69
+
70
+ puts output
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,20 @@
1
+ require 'eucalypt/eucalypt-blog/namespaces/blog/__base__'
2
+
3
+ module Eucalypt
4
+ module Generators
5
+ class Blog < Thor::Group
6
+ def views
7
+ config = {erb: ["<%= application :css, :js %>","<%= yield %>"]}
8
+ template File.join('views','article_layout.erb'), File.join('app','views','layouts','blog','article.erb'), config
9
+ template File.join('views','articles_layout.erb'), File.join('app','views','layouts','blog','articles.erb'), config
10
+
11
+ config = {erb: "<%= content %>"}
12
+ template File.join('views','article.erb'), File.join('app','views','blog','article.erb'), config
13
+
14
+ config = {erb: "<%= @articles %>"}
15
+ template File.join('views','articles.erb'), File.join('app','views','blog','articles.erb'), config
16
+ template File.join('views','search.erb'), File.join('app','views','blog','search.erb'), config
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,33 @@
1
+ class BlogController < Eucalypt::Controller(route: '<%= config[:route] %>')
2
+ helpers BlogHelper
3
+ using Array::DateSort
4
+
5
+ # Display all blog articles at this route
6
+ get '/' do
7
+ @articles = Blog.all.sort_by_date order: :descending
8
+ erb :'blog/articles', layout: :'layouts/blog/articles'
9
+ end
10
+
11
+ # Display a single blog article at this route
12
+ Blog.articles.each do |md|
13
+ article = Blog::Article.new md
14
+ get article.route do
15
+ @front_matter = article.front_matter
16
+ locals = {content: markdown(article.content), article: article}
17
+ erb :'blog/article', locals: locals, layout: :'layouts/blog/article'
18
+ end
19
+ end
20
+
21
+ # Search for blog articles by tag at this route
22
+ get '/search/:tag' do
23
+ @tag = params[:tag]
24
+ redirect to '/' unless @tag.match /\A[a-zA-Z]*[a-zA-Z0-9\\-_.]*[a-zA-Z0-9]\Z/
25
+ @articles = Blog.search(@tag).sort_by_date order: :descending
26
+ erb :'blog/search', layout: :'layouts/blog/articles'
27
+ end
28
+
29
+ # Redirect all other blog routes
30
+ get %r{/.*} do
31
+ redirect to '/'
32
+ end
33
+ end
@@ -0,0 +1,43 @@
1
+ require_relative '../spec_helper'
2
+ require 'front_matter_parser'
3
+
4
+ describe BlogController do
5
+ def app() BlogController end
6
+
7
+ ARTICLES = Eucalypt.glob('app', 'views', 'blog', 'markdown', '**', '*.md').map do |md|
8
+ FrontMatterParser::Parser.parse_file(md).front_matter.symbolize_keys
9
+ end
10
+
11
+ describe 'blog page' do
12
+ it "should display all posts" do
13
+ get '/'
14
+ expect(true).to be false
15
+ end
16
+ end
17
+
18
+ ARTICLES.each do |post|
19
+ subpath = post[:time].split(' ').first.gsub(?-,?/)
20
+
21
+ describe "Post: #{post[:title]}" do
22
+ before { get "/#{subpath}/#{post[:urltitle]}" }
23
+
24
+ it "should have a timestamp" do
25
+ expect(true).to be false
26
+ end
27
+
28
+ it "should have a title" do
29
+ expect(true).to be false
30
+ end
31
+
32
+ it "should have a description" do
33
+ expect(true).to be false
34
+ end
35
+
36
+ it "should have tags" do
37
+ post[:tags].each do |tag|
38
+ expect(true).to be false
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end