active_theme 0.5.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. data/.gitignore +8 -0
  2. data/.rspec +2 -0
  3. data/.rvmrc +1 -0
  4. data/.travis.yml +2 -0
  5. data/Gemfile +3 -0
  6. data/Gemfile.lock +91 -0
  7. data/LICENSE +21 -0
  8. data/README.textile +3 -0
  9. data/Rakefile +11 -0
  10. data/active_theme.gemspec +25 -0
  11. data/doc/README.textile +332 -0
  12. data/doc/REVIEW_NOTES +0 -0
  13. data/doc/TODO.textile +3 -0
  14. data/lib/active_theme.rb +58 -0
  15. data/lib/active_theme/action_controller.rb +32 -0
  16. data/lib/active_theme/action_mailer.rb +22 -0
  17. data/lib/active_theme/action_view.rb +59 -0
  18. data/lib/active_theme/assets_controller.rb +66 -0
  19. data/lib/active_theme/common_methods.rb +66 -0
  20. data/lib/active_theme/config.rb +74 -0
  21. data/lib/active_theme/interpolation.rb +11 -0
  22. data/lib/active_theme/railtie.rb +32 -0
  23. data/lib/active_theme/routes.rb +27 -0
  24. data/lib/active_theme/url_helpers.rb +27 -0
  25. data/lib/active_theme/version.rb +4 -0
  26. data/lib/generators/active_theme/create_generator.rb +14 -0
  27. data/lib/generators/active_theme/install_generator.rb +16 -0
  28. data/lib/generators/active_theme/templates/theme/images/.gitkeep +0 -0
  29. data/lib/generators/active_theme/templates/theme/javascripts/.gitkeep +0 -0
  30. data/lib/generators/active_theme/templates/theme/stylesheets/.gitkeep +0 -0
  31. data/lib/generators/active_theme/templates/theme/views/layouts/.gitkeep +0 -0
  32. data/lib/tasks/active_theme.rake +22 -0
  33. data/test/dummy_app/.gitignore +4 -0
  34. data/test/dummy_app/Gemfile +30 -0
  35. data/test/dummy_app/Rakefile +7 -0
  36. data/test/dummy_app/another_themes/another_default/images/logo.png +0 -0
  37. data/test/dummy_app/another_themes/another_default/images/nested/logo.png +0 -0
  38. data/test/dummy_app/another_themes/another_default/javascripts/app.js +1 -0
  39. data/test/dummy_app/another_themes/another_default/stylesheets/style.css +0 -0
  40. data/test/dummy_app/another_themes/another_default/stylesheets/style2.css +3 -0
  41. data/test/dummy_app/another_themes/another_default/views/layouts/default.html.erb +10 -0
  42. data/test/dummy_app/another_themes/another_default/views/products/index.html.erb +0 -0
  43. data/test/dummy_app/app/controllers/application_controller.rb +3 -0
  44. data/test/dummy_app/app/helpers/application_helper.rb +2 -0
  45. data/test/dummy_app/app/views/layouts/application.html.erb +14 -0
  46. data/test/dummy_app/config.ru +4 -0
  47. data/test/dummy_app/config/application.rb +42 -0
  48. data/test/dummy_app/config/boot.rb +13 -0
  49. data/test/dummy_app/config/database.yml +18 -0
  50. data/test/dummy_app/config/environment.rb +5 -0
  51. data/test/dummy_app/config/environments/development.rb +26 -0
  52. data/test/dummy_app/config/environments/production.rb +49 -0
  53. data/test/dummy_app/config/environments/test.rb +35 -0
  54. data/test/dummy_app/config/initializers/backtrace_silencers.rb +7 -0
  55. data/test/dummy_app/config/initializers/inflections.rb +10 -0
  56. data/test/dummy_app/config/initializers/mime_types.rb +5 -0
  57. data/test/dummy_app/config/initializers/secret_token.rb +7 -0
  58. data/test/dummy_app/config/initializers/session_store.rb +8 -0
  59. data/test/dummy_app/config/locales/en.yml +5 -0
  60. data/test/dummy_app/config/routes.rb +4 -0
  61. data/test/dummy_app/db/seeds.rb +7 -0
  62. data/test/dummy_app/empty_themes/.gitkeep +0 -0
  63. data/test/dummy_app/lib/tasks/.gitkeep +0 -0
  64. data/test/dummy_app/public/404.html +26 -0
  65. data/test/dummy_app/public/422.html +26 -0
  66. data/test/dummy_app/public/500.html +26 -0
  67. data/test/dummy_app/public/favicon.ico +0 -0
  68. data/test/dummy_app/public/images/rails.png +0 -0
  69. data/test/dummy_app/public/index.html +239 -0
  70. data/test/dummy_app/public/javascripts/application.js +2 -0
  71. data/test/dummy_app/public/javascripts/controls.js +965 -0
  72. data/test/dummy_app/public/javascripts/dragdrop.js +974 -0
  73. data/test/dummy_app/public/javascripts/effects.js +1123 -0
  74. data/test/dummy_app/public/javascripts/prototype.js +6001 -0
  75. data/test/dummy_app/public/javascripts/rails.js +175 -0
  76. data/test/dummy_app/public/robots.txt +5 -0
  77. data/test/dummy_app/public/stylesheets/.gitkeep +0 -0
  78. data/test/dummy_app/script/rails +6 -0
  79. data/test/dummy_app/themes/default/images/logo.png +0 -0
  80. data/test/dummy_app/themes/default/images/nested/logo.png +0 -0
  81. data/test/dummy_app/themes/default/javascripts/app.js +1 -0
  82. data/test/dummy_app/themes/default/javascripts/app.min.js +0 -0
  83. data/test/dummy_app/themes/default/stylesheets/images/logo.png +0 -0
  84. data/test/dummy_app/themes/default/stylesheets/style.css +0 -0
  85. data/test/dummy_app/themes/default/stylesheets/style2.css +3 -0
  86. data/test/dummy_app/themes/default/views/layouts/default.html.erb +10 -0
  87. data/test/dummy_app/themes/default/views/products/index.html.erb +0 -0
  88. data/test/lib/action_controller_test.rb +170 -0
  89. data/test/lib/action_mailer_test.rb +35 -0
  90. data/test/lib/action_view_test.rb +54 -0
  91. data/test/lib/assets_controller_test.rb +73 -0
  92. data/test/lib/common_methods_test.rb +28 -0
  93. data/test/lib/config_test.rb +26 -0
  94. data/test/lib/integration_test.rb +12 -0
  95. data/test/lib/routes_test.rb +40 -0
  96. data/test/lib/themes_for_rails_test.rb +18 -0
  97. data/test/support/extensions.rb +19 -0
  98. data/test/test_helper.rb +12 -0
  99. metadata +276 -0
File without changes
@@ -0,0 +1,3 @@
1
+ - Allow to change the way the view path is added. Before or after.
2
+
3
+ - Research how to integrate SASS to this scheme.
@@ -0,0 +1,58 @@
1
+ # encoding: utf-8
2
+ module ActiveTheme
3
+
4
+ class << self
5
+
6
+ def config
7
+ @config ||= ActiveTheme::Config.new
8
+ yield(@config) if block_given?
9
+ @config
10
+ end
11
+
12
+ def available_themes(&block)
13
+ Dir.glob(File.join(config.themes_path, "*"), &block)
14
+ end
15
+ alias each_theme_dir available_themes
16
+
17
+ def available_theme_names
18
+ available_themes.map {|theme| File.basename(theme) }
19
+ end
20
+
21
+ def add_themes_path_to_sass
22
+ if ActiveTheme.config.sass_is_available?
23
+ each_theme_dir do |dir|
24
+ if File.directory?(dir) # Need to get rid of the '.' and '..'
25
+
26
+ sass_dir = "#{dir}/stylesheets/sass"
27
+ css_dir = "#{dir}/stylesheets"
28
+
29
+ unless already_configured_in_sass?(sass_dir)
30
+ Sass::Plugin.add_template_location sass_dir, css_dir
31
+ end
32
+ end
33
+ end
34
+ else
35
+ raise "Sass is not available. What are you trying to do?"
36
+ end
37
+ end
38
+
39
+ def already_configured_in_sass?(sass_dir)
40
+ Sass::Plugin.template_location_array.map(&:first).include?(sass_dir)
41
+ end
42
+
43
+ end
44
+ end
45
+
46
+ require 'active_support/dependencies'
47
+ require 'active_theme/interpolation'
48
+ require 'active_theme/config'
49
+ require 'active_theme/common_methods'
50
+ require 'active_theme/url_helpers'
51
+
52
+ require 'active_theme/action_view'
53
+ require 'active_theme/assets_controller'
54
+ require 'active_theme/action_controller'
55
+ require 'active_theme/action_mailer'
56
+ require 'active_theme/railtie'
57
+ require 'active_theme/routes'
58
+
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+ module ActiveTheme
3
+
4
+ module ActionController
5
+
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+
10
+ include ActiveTheme::CommonMethods
11
+ include ActiveTheme::UrlHelpers
12
+
13
+ end
14
+
15
+ module ClassMethods
16
+
17
+ def theme(name, options = {})
18
+ before_filter(options) do |controller|
19
+ controller.set_theme(name)
20
+ end
21
+ end
22
+
23
+ end
24
+
25
+ def theme(name)
26
+ set_theme(name)
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+ module ActiveTheme
3
+
4
+ module ActionMailer
5
+
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ include ActiveTheme::ActionController
10
+ alias_method_chain :mail, :theme
11
+ end
12
+
13
+ def mail_with_theme(headers = {}, &block)
14
+ theme_opts = headers[:theme] || self.class.default[:theme]
15
+ theme(theme_opts) if theme_opts
16
+
17
+ mail_without_theme(headers, &block)
18
+ end
19
+
20
+ end
21
+
22
+ end
@@ -0,0 +1,59 @@
1
+ # encoding: utf-8
2
+ module ActiveTheme
3
+
4
+ module ActionView
5
+
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ include ActiveTheme::CommonMethods
10
+ end
11
+
12
+ def current_theme_stylesheet_path(asset)
13
+ base_theme_stylesheet_path(:theme => self.theme_name, :asset => "#{asset}.css")
14
+ end
15
+
16
+ def current_theme_javascript_path(asset)
17
+ base_theme_javascript_path(:theme => self.theme_name, :asset => "#{asset}.js")
18
+ end
19
+
20
+ def current_theme_image_path(asset)
21
+ base_theme_image_path(:theme => self.theme_name, :asset => asset)
22
+ end
23
+
24
+ def theme_stylesheet_path(asset, new_theme_name = self.theme_name)
25
+ base_theme_stylesheet_path(:theme => new_theme_name, :asset => "#{asset}.css")
26
+ end
27
+
28
+ def theme_javascript_path(asset, new_theme_name = self.theme_name)
29
+ base_theme_javascript_path(:theme => new_theme_name, :asset => "#{asset}.js")
30
+ end
31
+
32
+ def theme_image_path(asset, new_theme_name = self.theme_name)
33
+ base_theme_image_path(:theme => new_theme_name, :asset => asset)
34
+ end
35
+
36
+ def theme_image_tag(source, options = {})
37
+ image_tag(theme_image_path(source), options)
38
+ end
39
+
40
+ def theme_image_submit_tag(source, options = {})
41
+ image_submit_tag(theme_image_path(source), options)
42
+ end
43
+
44
+ def theme_javascript_include_tag(*files)
45
+ options = files.extract_options!
46
+ options.merge!({ :type => "text/javascript" })
47
+ files.collect! {|file| theme_javascript_path(file) }
48
+ javascript_include_tag(*files, options)
49
+ end
50
+
51
+ def theme_stylesheet_link_tag(*files)
52
+ options = files.extract_options!
53
+ options.merge!({ :type => "text/css" })
54
+ files.collect! {|file| theme_stylesheet_path(file) }
55
+ stylesheet_link_tag(*files, options)
56
+ end
57
+ end
58
+ end
59
+
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+ require "action_controller/metal"
3
+
4
+ module ActiveTheme
5
+ class AssetsController < ActionController::Base
6
+
7
+ def stylesheets
8
+ handle_asset("stylesheets")
9
+ end
10
+
11
+ def javascripts
12
+ handle_asset("javascripts")
13
+ end
14
+
15
+ def images
16
+ handle_asset("images")
17
+ end
18
+
19
+ private
20
+
21
+ def handle_asset(prefix)
22
+ asset, theme = params[:asset], params[:theme]
23
+ find_themed_asset(asset, theme, prefix) do |path, mime_type|
24
+ send_file path, :type => mime_type, :disposition => "inline"
25
+ end
26
+ end
27
+
28
+ def find_themed_asset(asset_name, asset_theme, asset_type, &block)
29
+ path = asset_path(asset_name, asset_theme, asset_type)
30
+ if File.exists?(path)
31
+ yield path, mime_type_for(request)
32
+ elsif File.extname(path).blank?
33
+ asset_name = "#{asset_name}.#{extension_from(request.path_info)}"
34
+ return find_themed_asset(asset_name, asset_theme, asset_type, &block)
35
+ else
36
+ render_not_found
37
+ end
38
+ end
39
+
40
+ def asset_path(asset_name, asset_theme, asset_type)
41
+ File.join(theme_asset_path_for(asset_theme), asset_type, asset_name)
42
+ end
43
+
44
+ def render_not_found
45
+ render :text => 'Not found', :status => 404
46
+ end
47
+
48
+ def mime_type_for(request)
49
+ existing_mime_type = mime_type_from_uri(request.path_info)
50
+ unless existing_mime_type.nil?
51
+ existing_mime_type.to_s
52
+ else
53
+ "image/#{extension_from(request.path_info)}"
54
+ end
55
+ end
56
+
57
+ def mime_type_from_uri(path)
58
+ extension = extension_from(path)
59
+ Mime::Type.lookup_by_extension(extension)
60
+ end
61
+
62
+ def extension_from(path)
63
+ File.extname(path).to_s[1..-1]
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+ module ActiveTheme
3
+ module CommonMethods
4
+
5
+ include ActiveTheme::Interpolation
6
+
7
+ def theme_name
8
+ @cached_theme_name ||= begin
9
+ case @theme_name
10
+ when Symbol then
11
+ self.respond_to?(@theme_name, true) ? self.send(@theme_name) : @theme_name.to_s
12
+ when String then @theme_name
13
+ else
14
+ nil
15
+ end
16
+ end
17
+ end
18
+
19
+ def theme_name=(name)
20
+ @theme_name = name
21
+ end
22
+
23
+ def set_theme(name)
24
+ self.theme_name = name
25
+ if valid_theme?
26
+ add_theme_view_path
27
+ end
28
+ end
29
+
30
+ public
31
+
32
+ def valid_theme?
33
+ !self.theme_name.nil?
34
+ end
35
+
36
+ # will add the view path for the current theme
37
+ def add_theme_view_path
38
+ add_theme_view_path_for(self.theme_name)
39
+ end
40
+
41
+ # will add the view path for a given theme name
42
+ def add_theme_view_path_for(name)
43
+ self.view_paths.insert 0, ::ActionView::FileSystemResolver.new(theme_view_path_for(name))
44
+ end
45
+
46
+ def public_theme_path
47
+ theme_view_path("/")
48
+ end
49
+
50
+ def theme_asset_path
51
+ theme_asset_path_for(theme_name)
52
+ end
53
+
54
+ def theme_view_path
55
+ theme_view_path_for(theme_name)
56
+ end
57
+
58
+ def theme_view_path_for(theme_name)
59
+ interpolate(ActiveTheme.config.views_dir, theme_name)
60
+ end
61
+
62
+ def theme_asset_path_for(theme_name)
63
+ interpolate(ActiveTheme.config.assets_dir, theme_name)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,74 @@
1
+ # encoding: utf-8
2
+ module ActiveTheme
3
+ class Config
4
+
5
+ attr_writer :base_dir, :themes_dir, :assets_dir, :views_dir, :themes_routes_dir
6
+ attr_accessor :use_sass, :default_theme
7
+
8
+ include Interpolation
9
+
10
+ def initialize(&block)
11
+ @use_sass = true
12
+ @default_theme = 'default'
13
+ yield if block_given?
14
+ end
15
+
16
+ def base_dir
17
+ @base_dir ||= Rails.root.to_s
18
+ end
19
+
20
+ # relative assets dir for view overloading support
21
+ # used for theme_view_path_for method to get theme path and add to view paths.
22
+ # Defaults to themes_dir for non asset pipeline users
23
+ #
24
+ # If you are using the Rails Asset Pipeline, this should be changed to the
25
+ # path of your assets in your app. For example, if you store your themes
26
+ # under /app/assets/themes - {Rails.root}/app/assets/themes
27
+ # you would need to set this to 'app/assets/themes' in your initializer config
28
+ def assets_dir
29
+ @assets_dir ||= ":root/themes/:name"
30
+ end
31
+
32
+ # relative views directory for theme views to be separated from assets
33
+ # used for Asset Pipeline support. Defaults to match {assets_dir}/views
34
+ def views_dir
35
+ @views_dir ||= ":root/themes/:name/views"
36
+ end
37
+
38
+ def themes_dir
39
+ @themes_dir ||= ":root/themes"
40
+ end
41
+
42
+ # Full path to themes
43
+ def themes_path
44
+ interpolate(themes_dir)
45
+ end
46
+
47
+ # This is the base themes dir that is used for mapping URL paths.
48
+ #
49
+ # If you are using the Rails Asset Pipeline, this should be changed to the
50
+ # prefix dir of your assets path. For example, if you store your themes
51
+ # under /app/assets/themes - {Rails.root}/app/assets/themes
52
+ # you would need to set this value to 'assets' to match up with the Sprockets
53
+ # path resolution process.
54
+
55
+ def themes_routes_dir
56
+ @themes_routes_dir ||= "themes"
57
+ end
58
+
59
+ def clear
60
+ @base_dir = nil
61
+ @themes_dir = nil
62
+ @assets_dir = nil
63
+ @views_dir = nil
64
+ end
65
+
66
+ def use_sass?
67
+ @use_sass and sass_is_available?
68
+ end
69
+
70
+ def sass_is_available?
71
+ !!defined?Sass::Plugin
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,11 @@
1
+ module ActiveTheme
2
+
3
+ module Interpolation
4
+
5
+ def interpolate(pattern, name = nil)
6
+ pattern.gsub(":root", ActiveTheme.config.base_dir).gsub(":name", name.to_s)
7
+ end
8
+
9
+ end
10
+
11
+ end
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+ module ActiveTheme
3
+ class Railtie < ::Rails::Railtie
4
+
5
+ config.active_theme = ActiveSupport::OrderedOptions.new
6
+
7
+ config.to_prepare do
8
+ ActiveTheme::Railtie.config.active_theme.each do |key, value|
9
+ ActiveTheme.config.send "#{key}=".to_sym, value
10
+ end
11
+
12
+ # Adding theme stylesheets path to sass, automatically.
13
+ ActiveTheme.add_themes_path_to_sass if ActiveTheme.config.use_sass?
14
+
15
+ ActiveSupport.on_load(:action_view) do
16
+ include ActiveTheme::ActionView
17
+ end
18
+
19
+ ActiveSupport.on_load(:action_controller) do
20
+ include ActiveTheme::ActionController
21
+ end
22
+
23
+ ActiveSupport.on_load(:action_mailer) do
24
+ include ActiveTheme::ActionMailer
25
+ end
26
+ end
27
+
28
+ rake_tasks do
29
+ load "tasks/active_theme.rake"
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+ module ActiveTheme
3
+ module Routes
4
+
5
+ def active_theme
6
+ theme_dir = ActiveTheme.config.themes_routes_dir
7
+ constraints = { :theme => /[\w\.]*/ }
8
+
9
+ match "#{theme_dir}/:theme/stylesheets/*asset" => 'active_theme/assets#stylesheets',
10
+ :as => :base_theme_stylesheet, :constraints => constraints
11
+ match "#{theme_dir}/:theme/javascripts/*asset" => 'active_theme/assets#javascripts',
12
+ :as => :base_theme_javascript, :constraints => constraints
13
+ match "#{theme_dir}/:theme/images/*asset" => 'active_theme/assets#images',
14
+ :as => :base_theme_image, :constraints => constraints
15
+ end
16
+
17
+ end
18
+ end
19
+
20
+ module ActionDispatch::Routing
21
+ class Mapper #:nodoc:
22
+
23
+ include ActiveTheme::Routes
24
+
25
+ end
26
+ end
27
+