eucalypt 0.1.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 (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