sections_rails 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.markdown +97 -0
  3. data/Rakefile +39 -0
  4. data/lib/generators/sections_generator.rb +70 -0
  5. data/lib/sections_rails.rb +19 -0
  6. data/lib/sections_rails/railtie.rb +9 -0
  7. data/lib/sections_rails/version.rb +3 -0
  8. data/lib/tasks/sections_rails_tasks.rake +102 -0
  9. data/spec/dummy/Rakefile +7 -0
  10. data/spec/dummy/app/assets/javascripts/application.js +9 -0
  11. data/spec/dummy/app/assets/stylesheets/application.css +7 -0
  12. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  13. data/spec/dummy/app/controllers/demos_controller.rb +5 -0
  14. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  15. data/spec/dummy/app/sections/hello_world/_hello_world.html.erb +6 -0
  16. data/spec/dummy/app/sections/hello_world/hello_world.css +9 -0
  17. data/spec/dummy/app/sections/hello_world/hello_world.js +10 -0
  18. data/spec/dummy/app/views/demos/index.html.erb +2 -0
  19. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  20. data/spec/dummy/config.ru +4 -0
  21. data/spec/dummy/config/application.rb +46 -0
  22. data/spec/dummy/config/boot.rb +10 -0
  23. data/spec/dummy/config/database.yml +25 -0
  24. data/spec/dummy/config/environment.rb +5 -0
  25. data/spec/dummy/config/environments/development.rb +30 -0
  26. data/spec/dummy/config/environments/production.rb +60 -0
  27. data/spec/dummy/config/environments/test.rb +39 -0
  28. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  29. data/spec/dummy/config/initializers/inflections.rb +10 -0
  30. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  31. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  32. data/spec/dummy/config/initializers/session_store.rb +8 -0
  33. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  34. data/spec/dummy/config/locales/en.yml +5 -0
  35. data/spec/dummy/config/routes.rb +60 -0
  36. data/spec/dummy/db/development.sqlite3 +0 -0
  37. data/spec/dummy/log/development.log +551 -0
  38. data/spec/dummy/public/404.html +26 -0
  39. data/spec/dummy/public/422.html +26 -0
  40. data/spec/dummy/public/500.html +26 -0
  41. data/spec/dummy/public/favicon.ico +0 -0
  42. data/spec/dummy/script/rails +6 -0
  43. data/spec/dummy/tmp/cache/assets/C73/0F0/sprockets%2F6f588d2eb67224099de772816998294a +0 -0
  44. data/spec/dummy/tmp/cache/assets/C9F/C10/sprockets%2F23fdd7731b76429ab821110239eb320f +0 -0
  45. data/spec/dummy/tmp/cache/assets/CBC/F40/sprockets%2Ff65678384223384d27c1be5bd58d527c +0 -0
  46. data/spec/dummy/tmp/cache/assets/CD6/B30/sprockets%2Fd360dea16179bf8b7c461301a3b48761 +0 -0
  47. data/spec/dummy/tmp/cache/assets/CD7/AC0/sprockets%2F2a8dc3c6e05c15a16948432386b61ad5 +0 -0
  48. data/spec/dummy/tmp/cache/assets/CE3/080/sprockets%2F7d4d7689d6fa8236f0b4848c03ba1215 +0 -0
  49. data/spec/dummy/tmp/cache/assets/CE5/100/sprockets%2F3255ada839df268ed863150542e87ac3 +0 -0
  50. data/spec/dummy/tmp/cache/assets/CE5/D30/sprockets%2F8c9834a63b25a66203918a75ff56e2ac +0 -0
  51. data/spec/dummy/tmp/cache/assets/D2D/C80/sprockets%2F5f8f97f91f67258b75bc96704a90ce1f +0 -0
  52. data/spec/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
  53. data/spec/dummy/tmp/cache/assets/D50/950/sprockets%2F93ba20a0001c0b50711bf58cf8e36bfb +0 -0
  54. data/spec/dummy/tmp/cache/assets/D54/ED0/sprockets%2F71c9fa01091d432b131da3bb73faf3d4 +0 -0
  55. data/spec/dummy/tmp/cache/assets/D84/210/sprockets%2Fabd0103ccec2b428ac62c94e4c40b384 +9648 -0
  56. data/spec/dummy/tmp/cache/assets/D93/630/sprockets%2F1203dbc01cf782fc6d17e5d7d8b53eb0 +0 -0
  57. data/spec/dummy/tmp/cache/assets/D94/460/sprockets%2Fd4ba18ed6ca55f732dba192d4b6036a8 +0 -0
  58. data/spec/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
  59. data/spec/spec_helper.rb +31 -0
  60. metadata +192 -0
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2011 Kevin Goslar
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/README.markdown ADDED
@@ -0,0 +1,97 @@
1
+ Ruby on Rails provides an amazing infrastructure and conventions for well structured server-side code.
2
+ It falls, however, short for the view layer.
3
+
4
+ _Partials_ provide a nice way to represent the HTML code of individual sections within complex web pages,
5
+ but no such facilities are available for the corresponding CSS and JavaScript.
6
+ This leaves the task of organizing the JS and CSS completely up to the user.
7
+
8
+ _Sections_rails_ fills this gap by adding infrastructure to the view layer of Ruby on Rails.
9
+ It allows to define and use the HTML, CSS, and JavaScript code of dedicated
10
+ sections of pages together in one place.
11
+
12
+
13
+ # Example
14
+
15
+ Let's assume a web page has amongst other things a navigation menu.
16
+ This menu requires certain HTML, CSS, and JavaScript code that is specific to it.
17
+ _Sections_rails_ allows to define this code as a _section_ inside the _/app_ folder:
18
+
19
+ /app/sections/menu/_menu.html.erb
20
+ menu.css
21
+ menu.js
22
+
23
+ To display this menu, simply do this in your view:
24
+
25
+ <%= section :menu %>
26
+
27
+ This inserts the partial as well as the JS and CSS files from _/app/sections/menu_ at this location.
28
+
29
+
30
+ # Installation
31
+
32
+ In your Gemfile:
33
+
34
+ gem 'sections_rails'
35
+
36
+ Then set up the directory structure:
37
+
38
+ $ rails generate sections
39
+
40
+ The generator does the following things:
41
+
42
+ 1. It creates a new folder __/app/sections__,
43
+ in which you put the source code for the different sections.
44
+
45
+ 2. It adds the folder _/app/sections_ to the asset pipeline by inserting this line into your _application.rb_ file:
46
+
47
+ config.assets.paths << 'app/sections'
48
+
49
+ 3. It optionally creates a demo section called _hello_world_.
50
+
51
+
52
+ # Usage
53
+
54
+ To use the "hello_world" section created by the sections generator, simply add it to the view:
55
+
56
+ <%= section :hello_world %>
57
+
58
+ If your section renders itself completely in JavaScript, you can omit its partial file.
59
+ In this case, the _sections_ command creates an empty div in the view.
60
+
61
+ <div class="hello_world"></div>
62
+
63
+
64
+ ## Asset precompilation
65
+
66
+ _Sections_rails_ provides facilities to include the assets of sections in the global asset
67
+ bundles for production mode.
68
+
69
+ 1. Run __rake sections:prepare__
70
+
71
+ This rake task creates helper files that tell the asset pipeline about the assets of the different sections.
72
+
73
+ * _/app/assets/javascripts/application_sections.js_ links to all JS files of all sections.
74
+ * _/app/assets/stylesheets/application_sections.js_ links to all CSS files of all sections.
75
+
76
+ 2. Include the generated helper files into your _application.js_ and _application.css_ files.
77
+
78
+ In application.js:
79
+
80
+ //= require application_sections
81
+
82
+ In application.css:
83
+
84
+ /*= require application_sections */
85
+
86
+ 3. Run __rake assets:precompile__ as usual.
87
+
88
+
89
+ # Missing features
90
+
91
+ _Sections_rails_ is in early development and far from complete. Missing features are:
92
+
93
+ * Support for multiple assets, and assets per section
94
+ * support for assets in different formats like CoffeeScript, Haml, Sass etc.
95
+ * Support for page-specific compiled asset files instead of one global one
96
+ * Better integration into the asset precompilation workflow.
97
+ * Include serverside controller logic for sections by integrating with https://github.com/apotonick/cells or something comparable
data/Rakefile ADDED
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'SectionsRails'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ Bundler::GemHelper.install_tasks
24
+
25
+ desc 'Default: run the specs and features.'
26
+ task :default => 'spec:unit' do
27
+ system("bundle exec rake spec")
28
+ end
29
+
30
+ namespace :spec do
31
+
32
+ desc "Run unit specs"
33
+ RSpec::Core::RakeTask.new('unit') do |t|
34
+ t.pattern = 'spec/{*_spec.rb}'
35
+ end
36
+ end
37
+
38
+ desc "Run the unit tests"
39
+ task :spec => ['spec:unit']
@@ -0,0 +1,70 @@
1
+ class SectionsGenerator < Rails::Generators::Base
2
+
3
+ def create_sections_folder
4
+ empty_directory "app/sections"
5
+ inject_into_file 'config/application.rb',
6
+ " config.assets.paths << 'app/sections'\n",
7
+ :after => /config.assets.enabled\s*=.*\n/
8
+ say ''
9
+ say ' I have made some modifications to '
10
+ say 'config/application.rb', Thor::Shell::Color::BOLD
11
+ say ' Please review them before submitting these changes to your code repository.'
12
+ say ''
13
+ end
14
+
15
+ def create_sample_section
16
+
17
+ # Ask the user.
18
+ return unless ['', 'y', 'yes'].include? ask('Do you want to create a sample section? [Yn]').downcase
19
+
20
+ # Create the sample section directory.
21
+ empty_directory "app/sections/hello_world"
22
+
23
+ # Create the partial.
24
+ create_file "app/sections/hello_world/_hello_world.html.erb", <<-END_STR
25
+ <!-- This file contains the HTML for the 'hello world' section. -->
26
+
27
+ <div class="hello_world">
28
+ <h2>Hello World!</h2>
29
+ This is content inside the hello world section!
30
+ </div>
31
+ END_STR
32
+
33
+ # Create the CSS file.
34
+ create_file "app/sections/hello_world/hello_world.css", <<-END_STR
35
+ /*
36
+ * This file contains the CSS for the 'hello world' section.
37
+ *
38
+ * Please note that all CSS in here should be relative to the container of the section,
39
+ * in this case the ".hello" class.
40
+ */
41
+
42
+ .hello_world { width: 300px; padding: 0 2ex 2ex; border: 2px dotted red; background-color: yellow; }
43
+ .hello_world .h2 { font-size: 1em; margin: 0 0 1ex; padding: 0; }
44
+ END_STR
45
+
46
+ # Create the JS file.
47
+ create_file "app/sections/hello_world/hello_world.js", <<-END_STR
48
+ /*
49
+ * This file contains the JavaScript for the 'hello world' section.
50
+ *
51
+ * Anything in here should be restrained to within the container of the section,
52
+ * i.e. the <div> with the class 'hello_world'.
53
+ */
54
+
55
+ $('.hello_world').click(function() {
56
+ alert('The Hello World section says hello to the world! :)');
57
+ });
58
+ END_STR
59
+
60
+ say ''
61
+ say ' A sample section has been created in '
62
+ say 'app/sections/sample_section', Thor::Shell::Color::BOLD
63
+ say ' To use it, simply put '
64
+ say '<%= section :sample %>', Thor::Shell::Color::BOLD
65
+ say ' in your view file.'
66
+ say ''
67
+ say ' Happy coding! :)'
68
+ say ''
69
+ end
70
+ end
@@ -0,0 +1,19 @@
1
+ module SectionsRails
2
+
3
+ require "sections_rails/railtie" if defined?(Rails)
4
+
5
+ def section name
6
+ out = []
7
+ out << javascript_include_tag("#{name}/#{name}") if File.exists? "#{Rails.root}/app/sections/#{name}/#{name}.js"
8
+ out << stylesheet_link_tag("#{name}/#{name}") if File.exists? "#{Rails.root}/app/sections/#{name}/#{name}.css"
9
+ if File.exists? "#{Rails.root}/app/sections/#{name}/_#{name}.html.erb"
10
+ out << render(:partial => "/../sections/#{name}/#{name}")
11
+ else
12
+ out << "<div class=\"#{name}\"></div>"
13
+ end
14
+ out.join("\n").html_safe
15
+ end
16
+
17
+ end
18
+
19
+ ActionView::Base.send :include, SectionsRails
@@ -0,0 +1,9 @@
1
+ require "rails/railtie"
2
+ module SectionsRails
3
+ class Railtie < Rails::Railtie
4
+
5
+ rake_tasks do
6
+ load "tasks/sections_rails_tasks.rake"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module SectionsRails
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,102 @@
1
+ namespace :sections do
2
+
3
+ desc "Prepares the assets for precompilation in a setup with a single application.js file"
4
+ task :prepare do
5
+
6
+ # Find all views in this app.
7
+ views = find_all_views 'app/views'
8
+
9
+ # Get all sections used in the views.
10
+ sections = views.map do |view|
11
+ find_sections_in_view IO.read "app/views/#{view}"
12
+ end.flatten
13
+
14
+ # Create the require file for application.js.
15
+ File.open "app/assets/javascripts/application_sections.js", 'w' do |file|
16
+ file.write "// THIS FILE IS AUTOMATICALLY CREATED BY THE SECTIONS PLUGIN.\n"
17
+ file.write "// PLEASE DO NOT MODIFY MANUALLY.\n"
18
+ file.write "//\n"
19
+ sections.each do |section|
20
+ if File.exists? "app/sections/#{section}/#{section}.js"
21
+ file.write "//= require ../../sections/#{section}/#{section} \n"
22
+ end
23
+ end
24
+ end
25
+
26
+ # Create the require file for application.css.
27
+ File.open "app/assets/stylesheets/application_sections.css", 'w' do |file|
28
+ file.write "/* \n"
29
+ file.write " * THIS FILE IS AUTOMATICALLY CREATED BY THE SECTIONS PLUGIN.\n"
30
+ file.write " * PLEASE DO NOT MODIFY MANUALLY.\n"
31
+ file.write " *\n"
32
+ sections.each do |section|
33
+ if File.exists? "app/sections/#{section}/#{section}.css"
34
+ file.write " *= require ../../sections/#{section}/#{section}\n"
35
+ end
36
+ end
37
+ file.write "*/"
38
+ end
39
+
40
+ # Make sure the require files are properly linked.
41
+ unless file_contains 'app/assets/javascripts/application.js', /application_sections/
42
+ puts "Please add the 'require' statement to 'application_sections.js' to 'application.js'."
43
+ end
44
+ unless file_contains 'app/assets/stylesheets/application.css', /application_sections/
45
+ puts "Please add the 'require' statement to 'application_sections.css' to 'application.css'."
46
+ end
47
+ end
48
+
49
+ desc "Prepares the assets for precompilation in a setup with multiple files per page."
50
+ task :prepare_pages do
51
+ root = 'app/views'
52
+
53
+ views = find_all_views root
54
+ sections_per_view = parse_views views
55
+
56
+ # Create the require files.
57
+ sections_per_view.each do |view, sections|
58
+
59
+ # Don't do anything if there are no sections in this view.
60
+ next if sections.blank?
61
+
62
+ # Don't do anything if the page has no page-specific JS file.
63
+ root_name = view[0..-10]
64
+ puts root_name
65
+ next unless File.exists? "app/pages/#{view}.js"
66
+ end
67
+ end
68
+
69
+ # Returns an array with the file name of all views in the given directory.
70
+ # Views are all files that end in .html.erb
71
+ def find_all_views root
72
+ result = []
73
+ Dir.entries(root).each do |dir|
74
+ next if ['.', '..', 'layouts'].include? dir
75
+ Dir.entries(File.join(root, dir)).each do |view_file|
76
+ next if ['.', '..'].include? view_file
77
+ result << File.join(dir, view_file)
78
+ end
79
+ end
80
+ result
81
+ end
82
+
83
+ def parse_views views
84
+ result = {}
85
+ views_to_parse.each do |view_to_parse|
86
+ view_text = IO.read(File.join root, view_to_parse)
87
+ result[view_to_parse] = find_sections_in_view view_text
88
+ end
89
+ result
90
+ end
91
+
92
+ # Returns an array with the name of all sections in the given view source.
93
+ def find_sections_in_view view_text
94
+ view_text.scan(/<%= section\s+['"](.*?)['"]\s*%>/).flatten.sort.uniq
95
+ end
96
+
97
+ # Returns whether the given file contains the given text somewhere in its content.
98
+ def file_contains file_name, text
99
+ IO.read(file_name) =~ text
100
+ end
101
+
102
+ end
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env rake
2
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
3
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
4
+
5
+ require File.expand_path('../config/application', __FILE__)
6
+
7
+ Dummy::Application.load_tasks
@@ -0,0 +1,9 @@
1
+ // This is a manifest file that'll be compiled into including all the files listed below.
2
+ // Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
3
+ // be included in the compiled file accessible from http://example.com/assets/application.js
4
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
5
+ // the compiled file.
6
+ //
7
+ //= require jquery
8
+ //= require jquery_ujs
9
+ //= require_tree .
@@ -0,0 +1,7 @@
1
+ /*
2
+ * This is a manifest file that'll automatically include all the stylesheets available in this directory
3
+ * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
4
+ * the top of the compiled file, but it's generally better to create a new file per style scope.
5
+ *= require_self
6
+ *= require_tree .
7
+ */
@@ -0,0 +1,3 @@
1
+ class ApplicationController < ActionController::Base
2
+ protect_from_forgery
3
+ end
@@ -0,0 +1,5 @@
1
+ class DemosController < ApplicationController
2
+ def index
3
+ end
4
+
5
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,6 @@
1
+ <!-- This file contains the HTML for the 'hello world' section. -->
2
+
3
+ <div class="hello_world">
4
+ <h2>Hello World!</h2>
5
+ This is content inside the hello world section!
6
+ </div>
@@ -0,0 +1,9 @@
1
+ /*
2
+ * This file contains the CSS for the 'hello world' section.
3
+ *
4
+ * Please note that all CSS in here should be relative to the container of the section,
5
+ * in this case the ".hello" class.
6
+ */
7
+
8
+ .hello_world { width: 300px; padding: 0 2ex 2ex; border: 2px dotted red; background-color: yellow; }
9
+ .hello_world .h2 { font-size: 1em; margin: 0 0 1ex; padding: 0; }
@@ -0,0 +1,10 @@
1
+ /*
2
+ * This file contains the JavaScript for the 'hello world' section.
3
+ *
4
+ * Anything in here should be restrained to within the container of the section,
5
+ * i.e. the <div> with the class 'hello_world'.
6
+ */
7
+
8
+ $('.hello_world').click(function() {
9
+ alert('The Hello World section says hello to the world! :)');
10
+ });