cornucopia 0.1.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +51 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +16 -0
  6. data/LICENSE.TXT +22 -0
  7. data/README.md +341 -0
  8. data/Rakefile +18 -0
  9. data/cornucopia.gemspec +39 -0
  10. data/lib/cornucopia.rb +18 -0
  11. data/lib/cornucopia/capybara/finder_diagnostics.rb +536 -0
  12. data/lib/cornucopia/capybara/finder_extensions.rb +89 -0
  13. data/lib/cornucopia/capybara/install_finder_extensions.rb +105 -0
  14. data/lib/cornucopia/capybara/install_matcher_extensions.rb +39 -0
  15. data/lib/cornucopia/capybara/matcher_extensions.rb +83 -0
  16. data/lib/cornucopia/capybara/page_diagnostics.rb +228 -0
  17. data/lib/cornucopia/cucumber_hooks.rb +38 -0
  18. data/lib/cornucopia/factory_girl/dynamic_association.rb +14 -0
  19. data/lib/cornucopia/rspec_hooks.rb +37 -0
  20. data/lib/cornucopia/site_prism/element_extensions.rb +273 -0
  21. data/lib/cornucopia/site_prism/install_element_extensions.rb +23 -0
  22. data/lib/cornucopia/site_prism/page_application.rb +126 -0
  23. data/lib/cornucopia/source_files/collapse.gif +0 -0
  24. data/lib/cornucopia/source_files/cornucopia.css +162 -0
  25. data/lib/cornucopia/source_files/expand.gif +0 -0
  26. data/lib/cornucopia/source_files/index_base.html +10 -0
  27. data/lib/cornucopia/source_files/index_contents.html +2 -0
  28. data/lib/cornucopia/source_files/more_info.js +87 -0
  29. data/lib/cornucopia/source_files/report_base.html +10 -0
  30. data/lib/cornucopia/source_files/report_contents.html +3 -0
  31. data/lib/cornucopia/spinach_hooks.rb +51 -0
  32. data/lib/cornucopia/util/configuration.rb +493 -0
  33. data/lib/cornucopia/util/configured_report.rb +520 -0
  34. data/lib/cornucopia/util/file_asset.rb +46 -0
  35. data/lib/cornucopia/util/generic_settings.rb +37 -0
  36. data/lib/cornucopia/util/log_capture.rb +97 -0
  37. data/lib/cornucopia/util/pretty_formatter.rb +580 -0
  38. data/lib/cornucopia/util/report_builder.rb +474 -0
  39. data/lib/cornucopia/util/report_formatters.rb +11 -0
  40. data/lib/cornucopia/util/report_table.rb +195 -0
  41. data/lib/cornucopia/version.rb +3 -0
  42. data/lib/tasks/cornucopia_tasks.rake +4 -0
  43. data/spec/dummy/README.rdoc +28 -0
  44. data/spec/dummy/Rakefile +6 -0
  45. data/spec/dummy/app/assets/images/.keep +0 -0
  46. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  47. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  48. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  49. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  50. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  51. data/spec/dummy/app/mailers/.keep +0 -0
  52. data/spec/dummy/app/models/.keep +0 -0
  53. data/spec/dummy/app/models/concerns/.keep +0 -0
  54. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  55. data/spec/dummy/bin/bundle +3 -0
  56. data/spec/dummy/bin/rails +4 -0
  57. data/spec/dummy/bin/rake +4 -0
  58. data/spec/dummy/config.ru +4 -0
  59. data/spec/dummy/config/application.rb +27 -0
  60. data/spec/dummy/config/boot.rb +5 -0
  61. data/spec/dummy/config/cucumber.yml +8 -0
  62. data/spec/dummy/config/database.yml +37 -0
  63. data/spec/dummy/config/environment.rb +5 -0
  64. data/spec/dummy/config/environments/development.rb +29 -0
  65. data/spec/dummy/config/environments/production.rb +80 -0
  66. data/spec/dummy/config/environments/test.rb +36 -0
  67. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  68. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  69. data/spec/dummy/config/initializers/inflections.rb +16 -0
  70. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  71. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  72. data/spec/dummy/config/initializers/session_store.rb +3 -0
  73. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  74. data/spec/dummy/config/locales/en.yml +23 -0
  75. data/spec/dummy/config/routes.rb +56 -0
  76. data/spec/dummy/db/schema.rb +16 -0
  77. data/spec/dummy/features/support/env.rb +66 -0
  78. data/spec/dummy/lib/assets/.keep +0 -0
  79. data/spec/dummy/lib/tasks/cucumber.rake +65 -0
  80. data/spec/dummy/public/404.html +58 -0
  81. data/spec/dummy/public/422.html +58 -0
  82. data/spec/dummy/public/500.html +57 -0
  83. data/spec/dummy/public/favicon.ico +0 -0
  84. data/spec/dummy/script/cucumber +10 -0
  85. data/spec/fixtures/sample_page.html +150 -0
  86. data/spec/lib/capybara/finder_diagnostics_spec.rb +517 -0
  87. data/spec/lib/capybara/finder_extensions_spec.rb +328 -0
  88. data/spec/lib/capybara/page_diagnostics_spec.rb +277 -0
  89. data/spec/lib/site_prism/element_extensions_spec.rb +290 -0
  90. data/spec/lib/site_prism/page_application_spec.rb +81 -0
  91. data/spec/lib/util/configuration_spec.rb +254 -0
  92. data/spec/lib/util/configured_report_spec.rb +1058 -0
  93. data/spec/lib/util/file_asset_spec.rb +86 -0
  94. data/spec/lib/util/generic_settings_spec.rb +48 -0
  95. data/spec/lib/util/log_capture_spec.rb +151 -0
  96. data/spec/lib/util/pretty_formatter_spec.rb +694 -0
  97. data/spec/lib/util/report_builder_spec.rb +983 -0
  98. data/spec/lib/util/report_formatters_spec.rb +13 -0
  99. data/spec/lib/util/report_table_exception_spec.rb +21 -0
  100. data/spec/lib/util/report_table_spec.rb +319 -0
  101. data/spec/pages/cornucopia_report_app.rb +10 -0
  102. data/spec/pages/google/email_page.rb +22 -0
  103. data/spec/pages/google/login_page.rb +25 -0
  104. data/spec/rails_helper.rb +43 -0
  105. data/spec/sample_report.rb +45 -0
  106. data/spec/spec_helper.rb +81 -0
  107. metadata +410 -0
@@ -0,0 +1,38 @@
1
+ require ::File.expand_path("../cornucopia", File.dirname(__FILE__))
2
+ require ::File.expand_path("../cornucopia/factory_girl/dynamic_association", File.dirname(__FILE__))
3
+
4
+ load ::File.expand_path("capybara/install_finder_extensions.rb", File.dirname(__FILE__))
5
+ load ::File.expand_path("capybara/install_matcher_extensions.rb", File.dirname(__FILE__))
6
+ load ::File.expand_path("site_prism/install_element_extensions.rb", File.dirname(__FILE__))
7
+
8
+ Around do |scenario, block|
9
+ seed_value = Cornucopia::Util::Configuration.seed ||
10
+ 100000000000000000000000000000000000000 + rand(899999999999999999999999999999999999999)
11
+
12
+ scenario.instance_variable_set :@seed_value, seed_value
13
+
14
+ block.call
15
+
16
+ if scenario.failed?
17
+ seed_value = scenario.instance_variable_get(:@seed_value)
18
+ puts ("random seed for testing was: #{seed_value}")
19
+ end
20
+ end
21
+
22
+ After do |scenario|
23
+ if scenario.failed?
24
+ Cornucopia::Util::ReportBuilder.current_report.
25
+ within_section("Test Error: #{scenario.feature.title}:#{scenario.title}") do |report|
26
+ configured_report = Cornucopia::Util::Configuration.report_configuration :cucumber
27
+
28
+ configured_report.add_report_objects scenario: scenario, cucumber: self
29
+ configured_report.generate_report(report)
30
+ end
31
+ end
32
+ end
33
+
34
+ at_exit do
35
+ Cornucopia::Util::ReportBuilder.current_report.close
36
+ end
37
+
38
+ Cornucopia::Util::ReportBuilder.new_report("cucumber_report")
@@ -0,0 +1,14 @@
1
+ module Cornucopia
2
+ module FactoryGirl
3
+ class DynamicAssociations
4
+ ##
5
+ # association creates an association which allows arguments or will call a block to create the
6
+ # associated object.
7
+ #
8
+ #
9
+ def association(name, options, &block)
10
+ options
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,37 @@
1
+ require ::File.expand_path("../cornucopia", File.dirname(__FILE__))
2
+ load ::File.expand_path("capybara/install_finder_extensions.rb", File.dirname(__FILE__))
3
+ load ::File.expand_path("capybara/install_matcher_extensions.rb", File.dirname(__FILE__))
4
+ load ::File.expand_path("site_prism/install_element_extensions.rb", File.dirname(__FILE__))
5
+
6
+ RSpec.configure do |config|
7
+ config.before(:suite) do |*args|
8
+ Cornucopia::Util::ReportBuilder.new_report("rspec_report")
9
+ end
10
+
11
+ config.after(:suite) do
12
+ Cornucopia::Util::ReportBuilder.current_report.close
13
+ end
14
+
15
+ config.around(:each) do |example|
16
+ @seed_value = Cornucopia::Util::Configuration.seed ||
17
+ 100000000000000000000000000000000000000 + rand(899999999999999999999999999999999999999)
18
+
19
+ srand(@seed_value)
20
+
21
+ example.run
22
+
23
+ test_example = example.example if example.respond_to?(:example)
24
+ test_example ||= self.example if self.respond_to?(:example)
25
+ if (test_example.exception)
26
+ puts ("random seed for testing was: #{@seed_value}")
27
+
28
+ Cornucopia::Util::ReportBuilder.current_report.
29
+ within_section("Test Error: #{test_example.full_description}") do |report|
30
+ configured_report = Cornucopia::Util::Configuration.report_configuration :rspec
31
+
32
+ configured_report.add_report_objects example: test_example
33
+ configured_report.generate_report(report)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,273 @@
1
+ require 'active_support/concern'
2
+
3
+ module Cornucopia
4
+ module SitePrism
5
+ module ElementExtensions
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ # patterned_elements defines a set of elements where the find pattern is based on the
10
+ # name that will be used for the element.
11
+ #
12
+ # element will be called once for each element with the find pattern where the string
13
+ # `%{element_name}` will be replace with the name for the element.
14
+ # The pattern must include `%{element_name}`.
15
+ #
16
+ # Parameters:
17
+ # pattern - String - This is the pattern that will be used to create the find option
18
+ # for the element. The pattern must include `%{element_name}`.
19
+ # elements - An array of symbols for the elements which will be defined.
20
+ # options - A set of options
21
+ # find_type: The type of the finder which will be used. The default is :css
22
+ # element_array: If not false or nil, this will cause the function to call `elements` instead
23
+ # of `element`
24
+ # additional_options: A hash of additional options which will be sent to element call.
25
+ #
26
+ # Examples:
27
+ # patterned_elements "\#%{element_name}",
28
+ # :user_first_name,
29
+ # :user_last_name,
30
+ # :user_middle_name,
31
+ # :user_sex
32
+ #
33
+ # Will call:
34
+ # element :user_first_name, "\#user_first_name"
35
+ # element :user_last_name, "\#user_last_name"
36
+ # element :user_middle_name, "\#user_middle_name"
37
+ # element :user_sex, "\#user_sex"
38
+ #
39
+ # patterned_elements "//option[contains(text(), \"${element_name}\")]",
40
+ # :Cincinati,
41
+ # :Chicago,
42
+ # :Denver,
43
+ # find_type: :xpath,
44
+ # additional_options: { visible: false }
45
+ #
46
+ # Will call:
47
+ # element :Cincinati, :xpath, "//option[contains(text(), \"Cincinati\")]", visible: false
48
+ # element :Chicago, :xpath, "//option[contains(text(), \"Chicago\")]", visible: false
49
+ # element :Denver, :xpath, "//option[contains(text(), \"Denver\")]", visible: false
50
+ def patterned_elements(pattern, *elements)
51
+ options = elements.extract_options!
52
+
53
+ unless pattern =~ /\%\{element_name\}/
54
+ raise Exception.new("Invalid pattern \"#{pattern}\". Pattern must contain \"%{element_name}\".")
55
+ end
56
+
57
+ element_function = :element
58
+ element_function = :elements if options[:element_array]
59
+
60
+ element_name_index = 0
61
+ options_array = []
62
+ if options[:find_type]
63
+ options_array << options[:find_type]
64
+ element_name_index += 1
65
+ end
66
+ options_array << :__blank__
67
+ options_array << pattern
68
+ options_array << options[:additional_options] if options[:additional_options]
69
+
70
+ elements.each do |element_name|
71
+ options_array[element_name_index] = element_name.to_s.gsub(/[-]/, "_").to_sym
72
+ options_array[element_name_index + 1] = pattern % { element_name: element_name }
73
+ send element_function, *options_array
74
+ end
75
+ end
76
+
77
+ # form_elements defines an ID finder for most form elements. Given a <model_name> and an
78
+ # array of <field_name>s, this function will call `element` once for each <field_name>
79
+ # defining an id based element assuming it was definied within a form for <model_name>.
80
+ #
81
+ # This is based off the fact that the IDs for most form elements follows a basic pattern
82
+ # of: "<model_name>_<field_name>".
83
+ #
84
+ # Parameters:
85
+ # model_name
86
+ # field_names
87
+ # options - A set of options
88
+ # element_array: If not false or nil, this will cause the function to call `elements` instead
89
+ # of `element`
90
+ #
91
+ # Example:
92
+ # form_elements :user,
93
+ # :first_name,
94
+ # :last_name,
95
+ # :middle_name,
96
+ # :sex
97
+ #
98
+ # Will call:
99
+ # element :first_name, "\#user_first_name"
100
+ # element :last_name, "\#user_last_name"
101
+ # element :middle_name, "\#user_middle_name"
102
+ # element :sex, "\#user_sex"
103
+ def form_elements(model_name, *field_names)
104
+ options = field_names.extract_options!
105
+
106
+ patterned_elements "\##{model_name}_%{element_name}", *field_names, options.slice(:element_array)
107
+ end
108
+
109
+ # id_elements defines an ID finder where the id of the element is the name for the element.
110
+ #
111
+ # Parameters:
112
+ # element_names - An array of elements to define where the id of the element is the same as the element name
113
+ # options - A set of options
114
+ # element_array: If not false or nil, this will cause the function to call `elements` instead
115
+ # of `element`
116
+ #
117
+ # Example:
118
+ # id_elements :some_object,
119
+ # :another_object
120
+ #
121
+ # Will call:
122
+ # element :some_object, "\#some_object"
123
+ # element :another_object, "\#another_object"
124
+ def id_elements(*element_names)
125
+ options = element_names.extract_options!
126
+
127
+ patterned_elements "\#%{element_name}", *element_names, options.slice(:element_array)
128
+ end
129
+
130
+ # class_elements defines an ID finder where the class of the element is the name for the element.
131
+ #
132
+ # Parameters:
133
+ # element_names - An array of elements to define where the id of the element is the same as the element name
134
+ # options - A set of options
135
+ # element_array: If not false or nil, this will cause the function to call `elements` instead
136
+ # of `element`
137
+ #
138
+ # Example:
139
+ # id_elements :some_object,
140
+ # :another_object
141
+ #
142
+ # Will call:
143
+ # element :some_object, ".some_object"
144
+ # element :another_object, ".another_object"
145
+ def class_elements(*element_names)
146
+ options = element_names.extract_options!
147
+
148
+ patterned_elements ".%{element_name}", *element_names, options.slice(:element_array)
149
+ end
150
+
151
+ # indexed_elements defines a set of elements where the finder pattern can be based off of
152
+ # an index value.
153
+ #
154
+ # This can be useful for table columns for example.
155
+ #
156
+ # Parameters:
157
+ # index_pattern - String - This is the pattern that will be used to create the find option
158
+ # for the element. The pattern must include `%{element_index}`.
159
+ # element_names - An array of symbols for the elements which will be defined.
160
+ # The name :__skip__ will be ignored. Ignored elements will always increment by one and
161
+ # will ignore the increment value.
162
+ # options - A set of options
163
+ # find_type: The type of the finder which will be used. The default is :css
164
+ # element_array: If not false or nil, this will cause the function to call `elements` instead
165
+ # of `element`
166
+ # additional_options: A hash of additional options which will be sent to element call.
167
+ # start_index: The start value for the first index element.
168
+ # increment: The amount the index will be incremented by each time.
169
+ #
170
+ # Examples:
171
+ # indexed_elements "\#my_table tr td:nth-child(%{element_index})",
172
+ # :first_name,
173
+ # :last_name,
174
+ # :middle_name,
175
+ # :sex
176
+ #
177
+ # Will call:
178
+ # element :first_name, "\#my_table tr td:nth-child(1)"
179
+ # element :last_name, "\#my_table tr td:nth-child(2)"
180
+ # element :middle_name, "\#my_table tr td:nth-child(3)"
181
+ # element :sex, "\#my_table tr td:nth-child(4)"
182
+ #
183
+ # indexed_elements "\#my_table tr td:nth-child(%{element_index})",
184
+ # :first_name,
185
+ # :last_name,
186
+ # :middle_name,
187
+ # :__skip__
188
+ # :sex
189
+ #
190
+ # Will call:
191
+ # element :first_name, "\#my_table tr td:nth-child(1)"
192
+ # element :last_name, "\#my_table tr td:nth-child(2)"
193
+ # element :middle_name, "\#my_table tr td:nth-child(3)"
194
+ # element :sex, "\#my_table tr td:nth-child(5)"
195
+ #
196
+ # indexed_elements "\#my_table tr td:nth-child(%{element_index})",
197
+ # :first_name,
198
+ # :last_name,
199
+ # :middle_name,
200
+ # :__skip__
201
+ # :sex,
202
+ # start_index: 4
203
+ # increment: 3
204
+ #
205
+ # Will call:
206
+ # element :first_name, "\#my_table tr td:nth-child(4)"
207
+ # element :last_name, "\#my_table tr td:nth-child(7)"
208
+ # element :middle_name, "\#my_table tr td:nth-child(10)"
209
+ # element :sex, "\#my_table tr td:nth-child(12)"
210
+ def indexed_elements(index_pattern, *element_names)
211
+ options = element_names.extract_options!
212
+
213
+ element_function = :element
214
+ element_function = :elements if options[:element_array]
215
+
216
+ element_index = options[:start_index] || 1
217
+ index_increment = options[:increment] || 1
218
+
219
+ unless index_pattern =~ /\%\{element_index\}/
220
+ raise Exception.new("Invalid index_pattern \"#{index_pattern}\". Pattern must contain \"%{element_index}\".")
221
+ end
222
+ raise Exception.new("Increment value may not be 0") if index_increment == 0
223
+
224
+ options_array = []
225
+ element_name_index = 0
226
+ if options[:find_type]
227
+ options_array << options[:find_type]
228
+ element_name_index += 1
229
+ end
230
+ options_array << :__blank__
231
+ options_array << index_pattern
232
+ options_array << options[:additional_options] if options[:additional_options]
233
+
234
+ element_names.each do |element_name|
235
+ if [:__blank__, :__skip__].include?(element_name)
236
+ element_index += 1
237
+ next
238
+ end
239
+
240
+ options_array[element_name_index] = element_name
241
+ options_array[element_name_index + 1] = index_pattern % { element_index: element_index }
242
+ send element_function, *options_array
243
+ element_index += index_increment
244
+ end
245
+ end
246
+
247
+ # I don't need this right now.
248
+ # I am thinking that I should try using x-path next time I need this.
249
+ #
250
+ # # immediate_child_element element_name, find_string == element element_name, "> #{find_string}"
251
+ # def immediate_child_element(element_name, *find_args)
252
+ # self.class_eval do
253
+ # elements "__cornucopia_element_#{element_name}", *find_args
254
+ # end
255
+ #
256
+ # define_method element_name.to_s do
257
+ # the_element = send("__cornucopia_element_#{element_name}").reduce([]) do |array, element|
258
+ # array << element if element.parent == self.root_element
259
+ # array
260
+ # end
261
+ #
262
+ # raise ::Capybara::ElementNotFound unless the_element.length > 0
263
+ # raise ::Capybara::Ambiguous unless the_element.length == 1
264
+ #
265
+ # the_element[0]
266
+ # end
267
+ # end
268
+ end
269
+ end
270
+ end
271
+ end
272
+
273
+ load ::File.expand_path("install_element_extensions.rb", File.dirname(__FILE__))
@@ -0,0 +1,23 @@
1
+ $cornucopia_element_extension_installed = false unless defined? $cornucopia_element_extension_installed
2
+
3
+ if Object.const_defined?("SitePrism") &&
4
+ ::SitePrism.const_defined?("Page") &&
5
+ !$cornucopia_element_extension_installed
6
+ module ::SitePrism
7
+ class Page
8
+ include Cornucopia::SitePrism::ElementExtensions
9
+ end
10
+ end
11
+ end
12
+
13
+ if Object.const_defined?("SitePrism") &&
14
+ ::SitePrism.const_defined?("Section") &&
15
+ !$cornucopia_element_extension_installed
16
+ $cornucopia_element_extension_installed = true
17
+
18
+ module ::SitePrism
19
+ class Section
20
+ include Cornucopia::SitePrism::ElementExtensions
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,126 @@
1
+ module Cornucopia
2
+ module SitePrism
3
+ # PageApplication is a class used to fetch page objects and memoize them
4
+ # without really having to know anything about them.
5
+ #
6
+ # This class is intended to be the base class for a page application object.
7
+ #
8
+ # An example of how it is designed to work is:
9
+ #
10
+ # class MyApplication < Cornucopia::SitePrism::PageApplication
11
+ # def pages_module
12
+ # MyPagesModule
13
+ # end
14
+ # end
15
+ #
16
+ # module MyPagesModule
17
+ # class MyPage < SitePrism::Page
18
+ # end
19
+ # end
20
+ #
21
+ # page = MyApplication.my_page
22
+ #
23
+ #
24
+ # The system works as follows:
25
+ # * Pages are defined as: BaseModule::SubModule::NamePage
26
+ # BaseModule:: is optional
27
+ # SubModule:: is optional and you can have as many levels as you want
28
+ # Name is the name of the page
29
+ # Page is recommended to distinguish pages from sections
30
+ #
31
+ # * A singleton instance of your application class is memoized. That instance
32
+ # is used to instantiate and memoize all of the page objects. Additional
33
+ # functions and properties which you may need may be added to this class.
34
+ # Remember, this singleton instance is instantiated once per test run and
35
+ # will be reused in multiple tests.
36
+ #
37
+ # * To get a page object, simply use your class object and call the underscored name
38
+ # of the page and its modules as a class method. The class method name will be
39
+ # deconstructed and constantized into a page object. The page object will be created
40
+ # once and then cached for future use. Use 2 underscores (__) between modules.
41
+ # To get the sample page it would be: MyApplication.sub_module__name_page
42
+ #
43
+ # All you have to do is define the page objects under a single module namespace and the
44
+ # application class will recognize the pages and return them.
45
+
46
+ class PageApplication
47
+ @@current_instances = {}
48
+
49
+ def pages_module
50
+ Object
51
+ end
52
+
53
+ class << self
54
+ def current_instance
55
+ @@current_instances[self.name] ||= self.new
56
+ end
57
+
58
+ # Redirect any non-class methods to the instance if the instance supports them.
59
+ def method_missing(method_sym, *arguments, &block)
60
+ if self.current_instance.respond_to?(method_sym, true)
61
+ self.current_instance.send(method_sym, *arguments)
62
+ else
63
+ super
64
+ end
65
+ end
66
+
67
+ def respond_to?(method_sym, include_private = false)
68
+ if self.current_instance.respond_to?(method_sym, include_private)
69
+ true
70
+ else
71
+ super
72
+ end
73
+ end
74
+ end
75
+
76
+ def is_page_name?(method_name)
77
+ is_page_name = false
78
+ if method_name =~ /^[@a-z0-9_]+$/i
79
+ base_class = pages_module
80
+
81
+ is_page_name = true
82
+ method_name.split("__").each do |module_name|
83
+ if module_name.blank?
84
+ is_page_name = false
85
+ break;
86
+ end
87
+
88
+ unless base_class.const_defined?(module_name.camelize)
89
+ is_page_name = false
90
+ break
91
+ end
92
+
93
+ base_class = "#{base_class}::#{module_name.camelize}".constantize
94
+ end
95
+ end
96
+
97
+ is_page_name
98
+ end
99
+
100
+ def method_missing(method_sym, *arguments, &block)
101
+ method_name = method_sym.to_s
102
+ if is_page_name?(method_name)
103
+ return_page = instance_variable_get("@#{method_name}")
104
+ unless return_page
105
+ return_page = "#{pages_module.to_s}::#{method_name.split("__").map(&:camelize).join("::")}".constantize.new
106
+ instance_variable_set("@#{method_name}", return_page)
107
+ end
108
+
109
+ return_page
110
+ else
111
+ super
112
+ end
113
+ end
114
+
115
+ def respond_to?(method_sym, include_private = false)
116
+ method_name = method_sym.to_s
117
+
118
+ if is_page_name?(method_name)
119
+ true
120
+ else
121
+ super
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end