cornucopia 0.1.12

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 (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