fortitude 0.9.5-java → 0.9.6-java

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +11 -0
  3. data/CONTRIBUTORS.md +4 -0
  4. data/fortitude.gemspec +1 -1
  5. data/lib/fortitude/rails/helpers.rb +20 -1
  6. data/lib/fortitude/rails/railtie.rb +2 -0
  7. data/lib/fortitude/rails/yielded_object_outputter.rb +3 -0
  8. data/lib/fortitude/version.rb +1 -1
  9. data/lib/fortitude/widget/integration.rb +15 -1
  10. data/lib/rails/generators/fortitude/base_view/base_view_generator.rb +13 -0
  11. data/lib/rails/generators/fortitude/base_view/templates/views_base.rb +230 -0
  12. data/lib/rails/generators/fortitude/controller/controller_generator.rb +18 -0
  13. data/lib/rails/generators/fortitude/controller/templates/view.html.rb +6 -0
  14. data/lib/rails/generators/fortitude/controller/templates/views_base.rb +230 -0
  15. data/lib/rails/generators/fortitude/mailer/mailer_generator.rb +26 -0
  16. data/lib/rails/generators/fortitude/mailer/templates/layout.html.rb +9 -0
  17. data/lib/rails/generators/fortitude/mailer/templates/view.html.rb +12 -0
  18. data/lib/rails/generators/fortitude/scaffold/scaffold_generator.rb +29 -0
  19. data/lib/rails/generators/fortitude/scaffold/templates/edit.html.rb +13 -0
  20. data/lib/rails/generators/fortitude/scaffold/templates/form.html.rb +44 -0
  21. data/lib/rails/generators/fortitude/scaffold/templates/index.html.rb +45 -0
  22. data/lib/rails/generators/fortitude/scaffold/templates/new.html.rb +11 -0
  23. data/lib/rails/generators/fortitude/scaffold/templates/show.html.rb +18 -0
  24. data/spec/rails/complex_helpers_system_spec.rb +6 -0
  25. data/spec/rails/data_passing_system_spec.rb +4 -0
  26. data/spec/rails/generators_system_spec.rb +166 -0
  27. data/spec/rails/templates/complex_helpers_system_spec/app/controllers/carryover_controller.rb +11 -0
  28. data/spec/rails/templates/complex_helpers_system_spec/app/views/carryover/show.html.rb +9 -0
  29. data/spec/rails/templates/complex_helpers_system_spec/app/views/complex_helpers_system_spec/form_for_test.rb +2 -0
  30. data/spec/rails/templates/complex_helpers_system_spec/config/routes.rb +6 -0
  31. data/spec/rails/templates/data_passing_system_spec/app/controllers/data_passing_system_spec_controller.rb +5 -0
  32. data/spec/rails/templates/data_passing_system_spec/app/views/data_passing_system_spec/nil_data_widget.rb +8 -0
  33. data/spec/rails/templates/generators_system_spec/config/environments/development.rb +39 -0
  34. metadata +30 -4
@@ -0,0 +1,26 @@
1
+ require 'rails/generators/erb/mailer/mailer_generator'
2
+
3
+ module Fortitude
4
+ module Generators
5
+ class MailerGenerator < ::Erb::Generators::MailerGenerator
6
+ source_root File.expand_path("../templates", __FILE__)
7
+
8
+ def create_view_base
9
+ generate "fortitude:base_view"
10
+ end
11
+
12
+ protected
13
+ def handler
14
+ :rb
15
+ end
16
+
17
+ def formats
18
+ [:html]
19
+ end
20
+
21
+ def format
22
+ :html
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,9 @@
1
+ class Views::Layouts::Mailer < Views::Base
2
+ def contents
3
+ html {
4
+ body {
5
+ yield
6
+ }
7
+ }
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ <%
2
+ our_class_name = class_name.camelize
3
+ our_class_name += "Mailer" if @path =~ %r{_mailer/}
4
+ -%>
5
+ class Views::<%= our_class_name %>::<%= @action.camelize %> < Views::Base
6
+ needs :greeting
7
+
8
+ def content
9
+ h1 "<%= class_name %>#<%= @action %>"
10
+ p "#{greeting}, find me in <%= @path %>"
11
+ end
12
+ end
@@ -0,0 +1,29 @@
1
+ require 'rails/generators/erb/scaffold/scaffold_generator'
2
+
3
+ module Fortitude
4
+ module Generators
5
+ class ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
6
+ source_root File.join(File.dirname(__FILE__), 'templates')
7
+
8
+ def copy_view_files
9
+ available_views.each do |view|
10
+ filename = filename_with_extensions(view)
11
+ template "#{view}.html.rb", File.join("app/views", controller_file_path, filename)
12
+ end
13
+ end
14
+
15
+ def create_view_base
16
+ generate "fortitude:base_view"
17
+ end
18
+
19
+ protected
20
+ def available_views
21
+ %w(index new show edit form)
22
+ end
23
+
24
+ def handler
25
+ :rb
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,13 @@
1
+ class Views::<%= plural_table_name.camelize %>::Edit < Views::Base
2
+ needs :<%= singular_table_name %>
3
+
4
+ def content
5
+ h1 "Editing <%= singular_table_name.titleize %>"
6
+
7
+ widget Views::<%= plural_table_name.camelize %>::Form, :<%= singular_table_name %> => <%= singular_table_name %>
8
+
9
+ link_to 'Show', <%= singular_table_name %>
10
+ text " | "
11
+ link_to 'Back', <%= index_helper %>_path
12
+ end
13
+ end
@@ -0,0 +1,44 @@
1
+ class Views::<%= plural_table_name.camelize %>::Form < Views::Base
2
+ needs :<%= singular_table_name %>
3
+
4
+ def content
5
+ form_for(<%= singular_table_name %>) do |f|
6
+ if <%= singular_table_name %>.errors.any?
7
+ div(:id => :error_explanation) {
8
+ h2 {
9
+ text pluralize(<%= singular_table_name %>.errors.count, "error")
10
+ text " prohibited this <%= singular_table_name %> from being saved:"
11
+ }
12
+
13
+ ul {
14
+ <%= singular_table_name %>.errors.full_messages.each do |message|
15
+ li message
16
+ end
17
+ }
18
+ }
19
+ end
20
+
21
+ <% attributes.each do |attribute| -%>
22
+ <% if attribute.respond_to?(:password_digest?) && attribute.password_digest? -%>
23
+ div(:class => :field) {
24
+ f.label :password
25
+ f.password_field :password
26
+ }
27
+
28
+ div(:class => :field) {
29
+ f.label :password_confirmation
30
+ f.password_field :password_confirmation
31
+ }
32
+ <% else -%>
33
+ <% name = if attribute.respond_to?(:column_name) then attribute.column_name else attribute.name end -%>
34
+ div(:class => :field) {
35
+ f.label :<%= name %>
36
+ f.<%= attribute.field_type %> :<%= name %>
37
+ }
38
+ <% end -%>
39
+ <% end -%>
40
+
41
+ div(:class => :actions) { f.submit }
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,45 @@
1
+ class Views::<%= plural_table_name.camelize %>::Index < Views::Base
2
+ needs :<%= plural_table_name %>, :notice => nil
3
+
4
+ def content
5
+ p notice, :id => :notice
6
+
7
+ h1 "<%= plural_table_name.titleize %>"
8
+
9
+ table {
10
+ thead {
11
+ tr {
12
+ <% attributes.reject { |a| a.respond_to?(:password_digest?) && a.password_digest? }.each do |attribute| -%>
13
+ th "<%= attribute.human_name %>"
14
+ <% end -%>
15
+ th
16
+ th
17
+ th
18
+ }
19
+ }
20
+
21
+ tbody {
22
+ <%= plural_table_name %>.each do |<%= singular_table_name %>|
23
+ tr {
24
+ <% attributes.reject { |a| a.respond_to?(:password_digest?) && a.password_digest? }.each do |attribute| -%>
25
+ td <%= singular_table_name %>.<%= attribute.name %>
26
+ <% end -%>
27
+ td {
28
+ link_to 'Show', <%= singular_table_name %>
29
+ }
30
+ td {
31
+ link_to 'Edit', edit_<%= singular_table_name %>_path(<%= singular_table_name %>)
32
+ }
33
+ td {
34
+ link_to 'Destroy', <%= singular_table_name %>, :method => :delete, :data => { :confirm => 'Are you sure?' }
35
+ }
36
+ }
37
+ end
38
+ }
39
+ }
40
+
41
+ br
42
+
43
+ link_to 'New <%= singular_table_name.titleize %>', new_<%= singular_table_name %>_path
44
+ end
45
+ end
@@ -0,0 +1,11 @@
1
+ class Views::<%= plural_table_name.camelize %>::New < Views::Base
2
+ needs :<%= singular_table_name %> => nil
3
+
4
+ def content
5
+ h1 "New <%= singular_table_name.titleize %>"
6
+
7
+ widget Views::<%= plural_table_name.camelize %>::Form, :<%= singular_table_name %> => <%= singular_table_name %>
8
+
9
+ link_to 'Back', <%= index_helper %>_path
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ class Views::<%= plural_table_name.camelize %>::Show < Views::Base
2
+ needs :<%= singular_table_name %>, :notice => nil
3
+
4
+ def content
5
+ p notice, :id => :notice
6
+
7
+ <% attributes.reject { |a| a.respond_to?(:password_digest?) && a.password_digest? }.each do |attribute| -%>
8
+ p {
9
+ strong "<%= attribute.human_name %>:"
10
+ text <%= singular_table_name %>.<%= attribute.name %>
11
+ }
12
+ <% end %>
13
+
14
+ link_to "Edit", edit_<%= singular_table_name %>_path(<%= singular_table_name %>)
15
+ text " | "
16
+ link_to 'Back', <%= index_helper %>_path
17
+ end
18
+ end
@@ -6,6 +6,7 @@ describe "Rails complex helper support", :type => :rails do
6
6
  %r{OUTSIDE_BEFORE\s*<form.*action=\"/complex_helpers_system_spec/form_for_test\".*
7
7
  INSIDE_BEFORE\s*
8
8
  FIRST:\s*<input.*person_first_name.*/>\s*
9
+ MIDDLE:\s*<input.*person_middle_name.*/>\s*
9
10
  LAST:\s*<input.*person_last_name.*/>\s*
10
11
  INSIDE_AFTER\s*
11
12
  </form>\s*
@@ -67,6 +68,11 @@ describe "Rails complex helper support", :type => :rails do
67
68
  </label>}mix)
68
69
  end
69
70
 
71
+ it "should allow implicitly carrying through things like IDs from one request to another" do
72
+ id = rand(1_000_000)
73
+ expect(rails_server.get("/carryover/#{id}")).to match(%r{Edit:\s*.*/carryover/#{id}/edit})
74
+ end
75
+
70
76
  it "should cache based on a name properly" do
71
77
  expect_match("cache_test?a=a1&b=b1",
72
78
  /before_cache\(a1,b1\).*inside_cache\(a1,b1\).*after_cache\(a1,b1\)/mi)
@@ -21,6 +21,10 @@ describe "Rails data-passing support", :type => :rails do
21
21
  expect_actionview_exception('omitted_variable', 'Fortitude::Errors::MissingNeed', /bar/)
22
22
  end
23
23
 
24
+ it "should not give you an error just because a variable is set to nil" do
25
+ expect_match("nil_data_widget", /foo is: &quot;the_foo&quot;/, /bar is: nil/)
26
+ end
27
+
24
28
  it "should not propagate un-needed variables" do
25
29
  expect_match("extra_variables", /foo method call: the_foo/, /foo instance var: nil/,
26
30
  /bar method call: NoMethodError/, /bar instance var: nil/,
@@ -0,0 +1,166 @@
1
+ describe "Rails generator support", :type => :rails do
2
+ # We use development mode so that we don't have to bounce the Rails server every time we
3
+ # generate something new.
4
+ uses_rails_with_template :generators_system_spec, :rails_env => :development
5
+
6
+ def views_base_path
7
+ @views_base_path ||= File.join(rails_server.rails_root, 'app', 'views', 'base.rb')
8
+ end
9
+
10
+ def clean_views_base!
11
+ File.delete(views_base_path) if File.exist?(views_base_path)
12
+ end
13
+
14
+ def ensure_views_base_is_correct!
15
+ expect(File.exist?(views_base_path)).to be_truthy
16
+
17
+ contents = File.read(views_base_path)
18
+ expect(contents).to match(/Views::Base\s*<\s*Fortitude::Widget\s*\n/)
19
+ expect(contents).to match(/doctype\s+:html5/)
20
+ end
21
+
22
+ def generate!(what)
23
+ rails_server.run_command_in_rails_root!("rails generate #{what}")
24
+ end
25
+
26
+ def ensure_file_matches!(subpath, regexp)
27
+ path = File.join(rails_server.rails_root, subpath)
28
+ expect(File.exist?(path)).to be_truthy
29
+
30
+ contents = File.read(path)
31
+ expect(contents).to match(regexp)
32
+ end
33
+
34
+ def ensure_action_matches!(subpath, regexp)
35
+ response = rails_server.get(subpath)
36
+ expect(response).to match(regexp)
37
+ response
38
+ end
39
+
40
+ describe "base view generation" do
41
+ it "should be able to generate a Views::Base file" do
42
+ clean_views_base!
43
+ generate!("fortitude:base_view")
44
+ ensure_views_base_is_correct!
45
+ end
46
+ end
47
+
48
+ describe "controller generation" do
49
+ it "should be able to generate a controller action that creates a Fortitude view" do
50
+ generate!("controller gen_con1 act_ion1")
51
+ ensure_file_matches!('app/views/gen_con1/act_ion1.html.rb', /Views::GenCon1::ActIon1\s*<\s*Views::Base/)
52
+ ensure_action_matches!('gen_con1/act_ion1', %r{<h1>\s*GenCon1#act_ion1\s*</h1>\s*<p>\s*Find me in app/views/gen_con1/act_ion1.html.rb\s*</p>}mi)
53
+ end
54
+
55
+ it "should generate a Views::Base file" do
56
+ clean_views_base!
57
+ generate!("controller gencon2 action2")
58
+ ensure_views_base_is_correct!
59
+ end
60
+
61
+ it "should not overwrite an existing Views::Base file" do
62
+ prior_contents = "class Views::Base < Fortitude::Widget\n doctype :html5\n def something\n end\nend"
63
+ File.open(views_base_path, 'w') { |f| f.puts prior_contents }
64
+
65
+ generate!("controller gencon3 action3")
66
+
67
+ expect(File.exist?(views_base_path)).to be_truthy
68
+ expect(File.read(views_base_path).strip).to eq(prior_contents.strip)
69
+ end
70
+
71
+ it "should allow switching back to ERb if desired" do
72
+ generate!("controller gen_con4 act_ion1 -e erb")
73
+ expect(File.exist?(File.join(rails_server.rails_root, 'app/views/gen_con4/act_ion1.html.rb'))).to be_falsey
74
+ expect(File.exist?(File.join(rails_server.rails_root, 'app/views/gen_con4/act_ion1.html.erb'))).to be_truthy
75
+ end
76
+ end
77
+
78
+ describe "mailer generation" do
79
+ def mailer_path_suffix
80
+ if rails_server.actual_rails_version =~ /^[34]\./
81
+ ""
82
+ else
83
+ "_mailer"
84
+ end
85
+ end
86
+
87
+ def mailer_class_suffix
88
+ if rails_server.actual_rails_version =~ /^[34]\./
89
+ ""
90
+ else
91
+ "Mailer"
92
+ end
93
+ end
94
+
95
+ it "should be able to generate a mailer that creates a Fortitude view and layout" do
96
+ generate!("mailer gen1 act_ion1")
97
+ ensure_file_matches!("app/views/gen1#{mailer_path_suffix}/act_ion1.html.rb", /Views::Gen1#{mailer_class_suffix}::ActIon1\s*<\s*Views::Base/)
98
+ end
99
+
100
+ it "should generate a Views::Base file" do
101
+ clean_views_base!
102
+ generate!("mailer gen1 act_ion1")
103
+ ensure_views_base_is_correct!
104
+ end
105
+
106
+ it "should not overwrite an existing Views::Base file" do
107
+ prior_contents = "class Views::Base < Fortitude::Widget\n doctype :html5\n def something\n end\nend"
108
+ File.open(views_base_path, 'w') { |f| f.puts prior_contents }
109
+
110
+ generate!("mailer gen1 act_ion1")
111
+
112
+ expect(File.exist?(views_base_path)).to be_truthy
113
+ expect(File.read(views_base_path).strip).to eq(prior_contents.strip)
114
+ end
115
+ end
116
+
117
+ describe "scaffold generation" do
118
+ it "should be able to generate a scaffold" do
119
+ generate!("scaffold MyModel foo:string bar:integer")
120
+
121
+ # We need to disable CSRF protection, since we're not using a session
122
+ application_controller = File.join(rails_server.rails_root, 'app', 'controllers', 'application_controller.rb')
123
+ application_controller_contents = File.read(application_controller)
124
+ if (! application_controller_contents.gsub!(/^\s*protect_from_forgery.*$/, "protect_from_forgery :with => :null_session"))
125
+ application_controller_contents.gsub!(/^end\Z/, " protect_from_forgery :with => :null_session\nend\n")
126
+ end
127
+ File.open(application_controller, 'w') { |f| f.puts application_controller_contents }
128
+
129
+ # Need this to create the table (which will be in SQLite by default, which is easy), or else
130
+ # the controller actions will fail since there will be no such table.
131
+ rails_server.run_command_in_rails_root!("rake db:migrate")
132
+
133
+ ensure_file_matches!('app/views/my_models/index.html.rb', %r{class Views::MyModels::Index < Views::Base})
134
+ ensure_file_matches!('app/views/my_models/show.html.rb', %r{class Views::MyModels::Show < Views::Base})
135
+ ensure_file_matches!('app/views/my_models/edit.html.rb', %r{class Views::MyModels::Edit < Views::Base})
136
+ ensure_file_matches!('app/views/my_models/new.html.rb', %r{class Views::MyModels::New < Views::Base})
137
+ ensure_file_matches!('app/views/my_models/form.html.rb', %r{class Views::MyModels::Form < Views::Base})
138
+
139
+ # Ruby 1.8.7 and Rails 3.0.x seems to have issues unless we do this, sadly...
140
+ rails_server.stop!
141
+ rails_server.start!
142
+
143
+ # This won't check that the views all have the right HTML in them (that's nearly impossible without
144
+ # just duplicating exactly what they're supposed to contain, right here), but it will check that they
145
+ # compile and produce some kind of HTML output.
146
+ ensure_action_matches!('my_models', %r{<h1>\s*My Models\s*</h1>}m)
147
+ new_html = ensure_action_matches!('my_models/new', %r{<form.*action=["']/my_models["']}m)
148
+
149
+ # Now, we try to create one
150
+ response = rails_server.post('my_models', :post_variables => {
151
+ 'my_model[foo]' => 'foo1', 'my_model[bar]' => 23456, :commit => 'Create My model' },
152
+ :ignore_status_code => true)
153
+
154
+ new_url = if (300..399).include?(Integer(response.code))
155
+ response['Location']
156
+ else
157
+ raise "Response didn't seem to give us a redirect: #{response.code.inspect} (from #{response.inspect})"
158
+ end
159
+ path = URI.parse(new_url).path
160
+
161
+ ensure_action_matches!(path, %r{foo1.*23456}m)
162
+ ensure_action_matches!("#{path}/edit", %r{Editing.*foo1.*23456}m)
163
+ ensure_action_matches!("my_models", %r{<h1>\s*My Models\s*</h1>.*foo1.*23456}m)
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,11 @@
1
+ class CarryoverController < ApplicationController
2
+ def show
3
+ # nothing here
4
+ @the_id = params[:id]
5
+ end
6
+
7
+ def edit
8
+ # nothing here
9
+ @the_id = params[:id]
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ class Views::Carryover::Show < Fortitude::Widgets::Html5
2
+ needs :the_id
3
+
4
+ def content
5
+ h1 "Show Carryover #{the_id}"
6
+
7
+ p "Edit: #{edit_carryover_path}"
8
+ end
9
+ end