shiny_themes 0.0.1

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 (65) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +34 -0
  4. data/lib/generators/shiny_themes/install_generator.rb +19 -0
  5. data/lib/generators/shiny_themes/templates/application.html.erb +14 -0
  6. data/lib/generators/shiny_themes/templates/manifest.css +14 -0
  7. data/lib/generators/shiny_themes/templates/manifest.js +9 -0
  8. data/lib/generators/shiny_themes/templates/manifest.scss +12 -0
  9. data/lib/generators/shiny_themes/templates/theme.yml +8 -0
  10. data/lib/generators/shiny_themes/theme_generator.rb +50 -0
  11. data/lib/shiny_themes.rb +8 -0
  12. data/lib/shiny_themes/engine.rb +56 -0
  13. data/lib/shiny_themes/renders_theme.rb +53 -0
  14. data/lib/shiny_themes/theme.rb +76 -0
  15. data/lib/shiny_themes/theme_config.rb +45 -0
  16. data/lib/shiny_themes/version.rb +3 -0
  17. data/test/dummy/README.rdoc +28 -0
  18. data/test/dummy/Rakefile +6 -0
  19. data/test/dummy/app/assets/javascripts/application.js +13 -0
  20. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  21. data/test/dummy/app/controllers/application_controller.rb +5 -0
  22. data/test/dummy/app/helpers/application_helper.rb +2 -0
  23. data/test/dummy/app/themes/test_theme/views/layouts/test_layout.html.erb +14 -0
  24. data/test/dummy/app/themes/test_theme/views/shiny_themes/test/test.html.erb +1 -0
  25. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  26. data/test/dummy/bin/bundle +3 -0
  27. data/test/dummy/bin/rails +4 -0
  28. data/test/dummy/bin/rake +4 -0
  29. data/test/dummy/bin/setup +29 -0
  30. data/test/dummy/config.ru +4 -0
  31. data/test/dummy/config/application.rb +29 -0
  32. data/test/dummy/config/boot.rb +5 -0
  33. data/test/dummy/config/environment.rb +5 -0
  34. data/test/dummy/config/environments/development.rb +38 -0
  35. data/test/dummy/config/environments/production.rb +76 -0
  36. data/test/dummy/config/environments/test.rb +42 -0
  37. data/test/dummy/config/initializers/assets.rb +11 -0
  38. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  39. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  40. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  41. data/test/dummy/config/initializers/inflections.rb +16 -0
  42. data/test/dummy/config/initializers/mime_types.rb +4 -0
  43. data/test/dummy/config/initializers/session_store.rb +3 -0
  44. data/test/dummy/config/initializers/wrap_parameters.rb +9 -0
  45. data/test/dummy/config/locales/en.yml +23 -0
  46. data/test/dummy/config/routes.rb +56 -0
  47. data/test/dummy/config/secrets.yml +22 -0
  48. data/test/dummy/config/theme.yml +4 -0
  49. data/test/dummy/log/test.log +11146 -0
  50. data/test/dummy/public/404.html +67 -0
  51. data/test/dummy/public/422.html +67 -0
  52. data/test/dummy/public/500.html +66 -0
  53. data/test/dummy/public/favicon.ico +0 -0
  54. data/test/dummy/tmp/app/themes/temp_theme/assets/javascripts/temp_theme/manifest.js +9 -0
  55. data/test/dummy/tmp/app/themes/temp_theme/assets/stylesheets/temp_theme/manifest.css +14 -0
  56. data/test/dummy/tmp/app/themes/temp_theme/views/layouts/temp_layout.html.erb +14 -0
  57. data/test/generators/shiny_themes/install_generator_test.rb +23 -0
  58. data/test/generators/shiny_themes/theme_generator_test.rb +59 -0
  59. data/test/lib/engine_test.rb +73 -0
  60. data/test/lib/renders_theme_test.rb +72 -0
  61. data/test/lib/theme_config_test.rb +60 -0
  62. data/test/lib/theme_test.rb +115 -0
  63. data/test/support/theme_test_helper.rb +23 -0
  64. data/test/test_helper.rb +19 -0
  65. metadata +169 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b00177d3c7213ebd42c0b4b3ed3b24319cb5c0b7
4
+ data.tar.gz: 0f8f7d64c1c48e74c01bc6345d20853f4e976f42
5
+ SHA512:
6
+ metadata.gz: f69b5ea0cc66fbd109b4e523f15c987ca7d715690a7616d776f89fc44c28639306ab76aa9d782e498dc8d2c2ad1204ad51af49d21be477a580b7157de40f6bbc
7
+ data.tar.gz: 6021d0920150c6d268e58f66a7c4deb66e58a0bac6f5e94fb8386f5af8337433aa25dd9e071d145e1af1367a2d623ea2ddc4ddd852de86b970f3eb52f105dfc3
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2016 shinylane
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,34 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'ShinyThemes'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+
21
+
22
+ Bundler::GemHelper.install_tasks
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'lib'
28
+ t.libs << 'test'
29
+ t.pattern = 'test/**/*_test.rb'
30
+ t.verbose = false
31
+ end
32
+
33
+
34
+ task default: :test
@@ -0,0 +1,19 @@
1
+ require 'rails/generators'
2
+
3
+ module ShinyThemes
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('../templates', __FILE__)
7
+
8
+ # Create default configuration file in config directory
9
+ def copy_config_file
10
+ copy_file "theme.yml", "config/theme.yml"
11
+ end
12
+
13
+ # Create the default themes directory under app
14
+ def create_themes_directory
15
+ empty_directory File.join("app", "themes")
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title><%= theme_name %></title>
5
+ <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
6
+ <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,14 @@
1
+ /* manifest stylesheet
2
+ * Use this to import all stylesheets for your theme. If you want to
3
+ * import stylesheets in different pages or layouts simply create another
4
+ * manifest file and begin the name with 'manifest_' or 'manifest-'
5
+ *
6
+ * The CSS extension manifests will use require comments that sprockets
7
+ * uses to import stylesheets. Generate a sass theme to use the sass
8
+ * import syntax.
9
+ *
10
+ * Require this stylesheet
11
+ *=require_self
12
+ * Require all stylesheets in the current directory
13
+ *=require_tree .
14
+ */
@@ -0,0 +1,9 @@
1
+ /* Manifest javascript
2
+ * Use this to import all javascripts for your theme. If you want to
3
+ * import javascript files in different pages or layouts simply create
4
+ * another manifest file and begin the name with 'manifest_' or 'manifest-'
5
+ */
6
+ // Require this JS file
7
+ //=require_self
8
+ // Require all javascripts in the current directory
9
+ //=require_tree .
@@ -0,0 +1,12 @@
1
+ /* manifest stylesheet
2
+ * Use this to import all stylesheets for your theme. If you want to
3
+ * import stylesheets in different pages or layouts simply create another
4
+ * manifest file and begin the name with 'manifest_' or 'manifest-'
5
+ *
6
+ * The scss extension uses sass import syntax to import stylesheets. If
7
+ * you want to use the sprockets require comment syntax create a manifest
8
+ * file with a .css extension (or rename this one).
9
+ */
10
+
11
+ /* Require all stylesheets in the current directory*/
12
+ @import "*/**";
@@ -0,0 +1,8 @@
1
+ ---
2
+ development: &development
3
+ name: 'default'
4
+ layout: 'application'
5
+ test:
6
+ <<: *development
7
+ production:
8
+ <<: *development
@@ -0,0 +1,50 @@
1
+ require 'rails/generators'
2
+
3
+ module ShinyThemes
4
+ module Generators
5
+ class ThemeGenerator < Rails::Generators::NamedBase
6
+ desc "This generator creates a new theme using the provided name and options"
7
+ source_root File.expand_path("../templates", __FILE__)
8
+ argument :name, type: :string
9
+ class_option :layout, type: :string, aliases: '-l', default: 'application', desc: 'Default layout for theme rendering'
10
+ class_option :sass, type: :boolean, aliasses: '-s', default: false, desc: 'Use sass for stylesheets'
11
+
12
+ def initialize(args, *options)
13
+ super
14
+ @theme_directory = Pathname(Rails.application.config.theme.path).join(name)
15
+ @views_directory = @theme_directory.join('views')
16
+ @assets_directory = @theme_directory.join('assets')
17
+ end
18
+
19
+ def create_theme_directories
20
+ # Create views directories
21
+ empty_directory @views_directory.join('layouts')
22
+ # Create Assets directories
23
+ empty_directory @assets_directory.join('images', name)
24
+ create_file @assets_directory.join('images', name, '.gitkeep'), nil
25
+ empty_directory @assets_directory.join('javascripts', name)
26
+ create_file @assets_directory.join('javascripts', name, '.gitkeep'), nil
27
+ empty_directory @assets_directory.join('stylesheets', name)
28
+ create_file @assets_directory.join('stylesheets', name, '.gitkeep'), nil
29
+ end
30
+
31
+ def create_js_files
32
+ copy_file 'manifest.js', "#{@assets_directory.join('javascripts', name, 'manifest.js')}"
33
+ end
34
+
35
+ def create_css_files
36
+ return if options[:sass]
37
+ copy_file 'manifest.css', "#{@assets_directory.join('stylesheets', name, 'manifest.css')}"
38
+ end
39
+
40
+ def create_sass_files
41
+ return unless options[:sass]
42
+ copy_file 'manifest.scss', "#{@assets_directory.join('stylesheets', name, 'manifest.scss')}"
43
+ end
44
+
45
+ def create_layout_file
46
+ copy_file 'application.html.erb', "#{@views_directory.join('layouts', "#{options[:layout]}.html.erb")}"
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,8 @@
1
+ require 'active_model'
2
+ require 'active_support/concern'
3
+ require 'shiny_themes/engine'
4
+
5
+ module ShinyThemes
6
+ autoload :Theme, 'shiny_themes/theme'
7
+ autoload :RendersTheme, 'shiny_themes/renders_theme'
8
+ end
@@ -0,0 +1,56 @@
1
+ require 'shiny_themes/theme_config'
2
+
3
+ module ShinyThemes
4
+ # Engine defines configuration and populates from the theme.yml config file.
5
+ # The class also updates the asset pipeline to include theme directories and files
6
+ # as well as including the RendersTheme module in ActionController::Base.
7
+ class Engine < ::Rails::Engine
8
+ # Class methods to help manage the rails config and the associated YAML file.
9
+ class << self
10
+ def theme_config
11
+ @theme_config ||= ShinyThemes::ThemeConfig.new
12
+ end
13
+
14
+ def default_options
15
+ { path: File.join('app', 'themes'),
16
+ asset_directories: %w(images stylesheets javascripts) }
17
+ end
18
+ end
19
+
20
+ initializer 'shiny_themes.theme_config' do |_|
21
+ Engine.theme_config.load
22
+ end
23
+
24
+ initializer 'shiny_themes.assets_path' do |app|
25
+ Dir.glob(Rails.root.join(app.config.theme.path, '*', 'assets', '**', '*')) do |dir|
26
+ # Add all themes directories and sub-directories to asset pipeline which
27
+ # makes it necessary to restart the application on theme installation
28
+ app.config.assets.paths << dir if Pathname(dir).directory?
29
+ end
30
+ end
31
+
32
+ initializer 'shiny_themes.precompile_assets' do |app|
33
+ app.config.assets.precompile << Proc.new do |path, filename|
34
+ # Precompile if the asset is under the themes directory and is either an
35
+ # image a manifest file or a non css/js asset.
36
+ if path =~ /#{app.config.theme.path}/
37
+ if !%w(.js .css).include?(File.extname(filename))
38
+ true
39
+ elsif path =~ /^[^\/]+\/manifest((_|-).+)?\.(js|css)$/ # named or starts with manifest
40
+ true
41
+ else
42
+ false
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ initializer 'shiny_themes.application_controller' do |_|
49
+ ActiveSupport.on_load :action_controller do
50
+ ActionController::Base.class_eval do
51
+ include RendersTheme
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,53 @@
1
+ module ShinyThemes
2
+ # RendersTheme concern
3
+ # Included into ActionController::Base providing a theme class variable for controllers.
4
+ # This theme defines a view path for templates and a layout to render with.
5
+ module RendersTheme
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ cattr_accessor :theme
10
+ # Create a new theme which will use Rails.application.config.theme settings
11
+ self.theme = Theme.new
12
+ layout Proc.new { |controller| controller.class.theme.layout }
13
+ prepend_before_action do |controller|
14
+ controller.prepend_view_path controller.class.theme.views_path
15
+ end
16
+ end
17
+
18
+ # @return [String] the current theme name
19
+ def current_theme_name
20
+ self.class.theme.name
21
+ end
22
+
23
+ # @return [String] the current theme default layout
24
+ def current_theme_layout
25
+ self.class.theme.layout
26
+ end
27
+
28
+ # Update the current theme for the controller and optionally save
29
+ # @param name [String] The name of the new theme
30
+ # @param options [Hash] Options hash
31
+ # @option options [String] :layout ('application') Default layout for theme
32
+ # @option options [Boolean] :dont_save (false) Dont save the update to the theme.yml config
33
+ # @return (Theme) the theme for the controller
34
+ def update_current_theme(name, options = {})
35
+ self.class.renders_theme(name, options)
36
+ Rails.application.config.theme.name = current_theme_name
37
+ Rails.application.config.theme.layout = current_theme_layout
38
+ ShinyThemes::Engine.theme_config.save unless options[:dont_save]
39
+ self.class.theme # return current theme object
40
+ end
41
+
42
+ module ClassMethods
43
+ # Use the theme and options for all rendering in this controller
44
+ # @param name [String] the name of the new theme
45
+ # @param options [Hash] Options hash
46
+ # option options [String] :layout ('application') Default layout for theme
47
+ # @return (Theme) the theme for the controller
48
+ def renders_theme(name, options = {})
49
+ self.theme = Theme.new(options.merge(name: name, layout: options[:layout]))
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,76 @@
1
+ module ShinyThemes
2
+ # Theme model class which is meant to be associated with one or more
3
+ # controllers. This theme "contains" assets (css, js, etc) as well as any
4
+ # views the them overrides and/or defines.
5
+ class Theme
6
+ include ActiveModel::Validations
7
+ # @return [String] the name of the theme which must match the root directory
8
+ # name where theme files are located. Defaults to config.theme.name value
9
+ attr_reader :name
10
+ # @return [String]] the name of the default layout to use. Defaults to
11
+ # config.theme.layout or 'application' if this does not exist
12
+ attr_accessor :layout
13
+
14
+ validates_presence_of :name, :layout
15
+ # 'views' directory must exist in the theme directory 'name/views' where
16
+ # name is the theme name
17
+ validate :views_directory_exists
18
+ # 'assets' directory must exist in the theme directory 'name/assets' where
19
+ # name is the theme name
20
+ validate :assets_directory_exists
21
+ # all Rails.application.config.theme.asset_directories must exist under
22
+ # 'name/assets' and must have a namespaced directory that shares the name of
23
+ # the theme. For example the images directory should look like -
24
+ # 'name/assets/images/name' where name is the theme name.
25
+ validate do |theme|
26
+ Rails.application.config.theme.asset_directories.each do |directory|
27
+ unless theme.asset_path.join(directory).exist? &&
28
+ theme.asset_path.join(directory, name).exist?
29
+ theme.errors.add(:base, "Missing or invalid #{directory} asset directory for theme")
30
+ end
31
+ end
32
+ end
33
+
34
+ # @param options [Hash] initialization options
35
+ # @option options [String] :name (Rails.application.config.theme.name) The 1
36
+ # name of the theme.
37
+ # @option options [String] :layout (Rails.application.config.theme.layout ||
38
+ # 'application') The name of the default layout.
39
+ # @option options [String] : :theme_path (Rails.application.config.theme.path)
40
+ # The path to the theme's parent directory.
41
+ def initialize(options = {})
42
+ @name = options[:name] || Rails.application.config.theme.name
43
+ @layout = options[:layout] || Rails.application.config.theme.layout || 'application'
44
+ @theme_path = options[:theme_path] || Rails.application.config.theme.path
45
+ end
46
+
47
+ # @return [Pathname] Path to the theme's root directory
48
+ def path
49
+ Rails.root.join(@theme_path, @name)
50
+ end
51
+
52
+ # @return [Pathname] Path to the theme's view directory
53
+ def views_path
54
+ path.join('views')
55
+ end
56
+
57
+ # @return [Pathname] Path to the theme's assets directory
58
+ def asset_path
59
+ path.join('assets')
60
+ end
61
+
62
+ protected
63
+
64
+ def views_directory_exists
65
+ unless views_path.exist? && views_path.directory?
66
+ errors.add(:base, "Missing theme views directory")
67
+ end
68
+ end
69
+
70
+ def assets_directory_exists
71
+ unless asset_path.exist? && asset_path.directory?
72
+ errors.add(:base, "Missing theme assets directory")
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,45 @@
1
+ module ShinyThemes
2
+ class ThemeConfig
3
+ attr_accessor :defaults
4
+ # Create the ordered options, populate with provided hash and load YAML file
5
+ # options.
6
+ # @param default_options [Hash] (Hash.new) - Options to populate the theme
7
+ # config with.
8
+ # @options default_options [String] :path The path relative to the rails root
9
+ # where templates are installed
10
+ # @options default_options [Array(String)] :asset_directories Names of
11
+ # directories containing assets for the theme relative to the 'assets'
12
+ # directory.
13
+ def initialize(defaults = Engine.default_options)
14
+ unless Rails.application.config.try(:theme)
15
+ Rails.application.config.theme = ActiveSupport::OrderedOptions.new
16
+ end
17
+ @defaults = defaults
18
+ end
19
+
20
+ # Load the theme.yml file and merge it with the theme configuration
21
+ def load
22
+ new_config = full_config[Rails.env].deep_symbolize_keys!
23
+ # Honor values in config file over defaults
24
+ @defaults.reject! { |k, _| new_config.keys.include?(k) }
25
+ Rails.application.config.theme.merge!(@defaults.merge(new_config))
26
+ end
27
+
28
+ # Save the current state of the theme config to the theme.yml file
29
+ def save
30
+ # Don't save default values
31
+ save_config = Rails.application.config.theme.reject { |k, _| @defaults.keys.include?(k) }
32
+ full_config[Rails.env].merge!(save_config)
33
+ File.open(config_pathname, 'w') { |f| f << full_config.to_yaml }
34
+ end
35
+
36
+ # The pathname where the theme config file can be found
37
+ def config_pathname
38
+ Rails.root.join('config', 'theme.yml')
39
+ end
40
+
41
+ def full_config
42
+ @full_config ||= YAML.load(File.open(config_pathname))
43
+ end
44
+ end
45
+ end