brut 0.0.12 → 0.0.20

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +4 -6
  3. data/brut.gemspec +1 -3
  4. data/lib/brut/back_end.rb +7 -0
  5. data/lib/brut/cli/apps/scaffold.rb +16 -24
  6. data/lib/brut/framework/config.rb +4 -43
  7. data/lib/brut/framework/mcp.rb +1 -1
  8. data/lib/brut/front_end/asset_path_resolver.rb +15 -0
  9. data/lib/brut/front_end/component.rb +66 -234
  10. data/lib/brut/front_end/components/constraint_violations.rb +9 -9
  11. data/lib/brut/front_end/components/form_tag.rb +16 -28
  12. data/lib/brut/front_end/components/i18n_translations.rb +12 -13
  13. data/lib/brut/front_end/components/input.rb +0 -1
  14. data/lib/brut/front_end/components/inputs/csrf_token.rb +2 -2
  15. data/lib/brut/front_end/components/inputs/radio_button.rb +6 -6
  16. data/lib/brut/front_end/components/inputs/select.rb +13 -20
  17. data/lib/brut/front_end/components/inputs/text_field.rb +18 -33
  18. data/lib/brut/front_end/components/inputs/textarea.rb +11 -26
  19. data/lib/brut/front_end/components/locale_detection.rb +2 -2
  20. data/lib/brut/front_end/components/page_identifier.rb +3 -5
  21. data/lib/brut/front_end/components/{time.rb → time_tag.rb} +13 -10
  22. data/lib/brut/front_end/components/traceparent.rb +5 -6
  23. data/lib/brut/front_end/generic_response.rb +33 -0
  24. data/lib/brut/front_end/handler.rb +2 -0
  25. data/lib/brut/front_end/http_method.rb +4 -0
  26. data/lib/brut/front_end/inline_svg_locator.rb +21 -0
  27. data/lib/brut/front_end/layout.rb +3 -0
  28. data/lib/brut/front_end/page.rb +16 -29
  29. data/lib/brut/front_end/request_context.rb +15 -0
  30. data/lib/brut/front_end/routing.rb +3 -2
  31. data/lib/brut/front_end.rb +41 -0
  32. data/lib/brut/i18n/base_methods.rb +14 -8
  33. data/lib/brut/i18n/for_back_end.rb +5 -0
  34. data/lib/brut/i18n/for_cli.rb +2 -1
  35. data/lib/brut/i18n/for_html.rb +9 -1
  36. data/lib/brut/i18n.rb +1 -0
  37. data/lib/brut/sinatra_helpers.rb +14 -7
  38. data/lib/brut/spec_support/component_support.rb +9 -9
  39. data/lib/brut/spec_support/e2e_support.rb +4 -0
  40. data/lib/brut/spec_support/matchers/have_i18n_string.rb +5 -0
  41. data/lib/brut/spec_support/rspec_setup.rb +1 -0
  42. data/lib/brut/spec_support.rb +4 -3
  43. data/lib/brut/version.rb +1 -1
  44. data/lib/brut.rb +2 -45
  45. metadata +16 -43
  46. data/lib/brut/front_end/template.rb +0 -47
  47. data/lib/brut/front_end/templates/block_filter.rb +0 -61
  48. data/lib/brut/front_end/templates/erb_engine.rb +0 -26
  49. data/lib/brut/front_end/templates/erb_parser.rb +0 -84
  50. data/lib/brut/front_end/templates/escapable_filter.rb +0 -20
  51. data/lib/brut/front_end/templates/html_safe_string.rb +0 -68
  52. data/lib/brut/front_end/templates/locator.rb +0 -60
@@ -14,7 +14,6 @@
14
14
  # @see Brut::FrontEnd::Component
15
15
  class Brut::FrontEnd::Page < Brut::FrontEnd::Component
16
16
  include Brut::FrontEnd::HandlingResults
17
- using Brut::FrontEnd::Templates::HTMLSafeString::Refinement
18
17
 
19
18
  # Returns the name of the layout for this page. This string is used to find an ERB file in `app/src/front_end/layouts`. Every page
20
19
  # must have a layout. If you wish to render a page with no layout, create an empty layout in your app and use that.
@@ -31,43 +30,35 @@ class Brut::FrontEnd::Page < Brut::FrontEnd::Component
31
30
  # @return [URI|Brut::FrontEnd::HttpStatus|Object] If you return a `URI` (mostly likely by returning the result of calling {Brut::FrontEnd::HandlingResults#redirect_to}), the user is redirected and {#render} is never called. If you return a {Brut::FrontEnd::HttpStatus} (mostly likely by returning the result of calling {Brut::FrontEnd::HandlingResults#http_status}), {#render} is skipped and that status is returned with no content. If anything else is returned, {#render} is called as normal.
32
31
  def before_render = nil
33
32
 
34
- # @!visibility private
33
+ def with_layout(&block)
34
+ layout_class = Module.const_get(
35
+ layout_class = RichString.new([
36
+ self.layout,
37
+ "layout"
38
+ ].join("_")).camelize
39
+ )
40
+ render layout_class.new(page_name:,&block)
41
+ end
42
+
43
+
35
44
  def handle!
36
45
  case before_render
37
46
  in URI => uri
38
- Brut.container.instrumentation.add_event("before_render got a URI", uri: uri)
39
47
  uri
40
48
  in Brut::FrontEnd::HttpStatus => http_status
41
- Brut.container.instrumentation.add_event("before_render got status", http_status: http_status)
42
49
  http_status
43
50
  else
44
- render
51
+ self.call
45
52
  end
46
53
  end
47
54
 
48
- # The core method of a page, which overrides {Brut::FrontEnd::Component#render}. This is expected to return
49
- # a string to be sent as a response to an HTTP request. Generally, you should not call this method as it is
50
- # called by Brut when your page is requested.
51
- #
52
- # Also, generally don't override this unles you need to do something unusual. Overriding this will completely bypass the layout
53
- # system and skip all ERB processing. Unlike {Brut::FrontEnd::Component#render}, overriding this method does not provide access to injected data from the request context.
54
- #
55
- # @return [Brut::FrontEnd::Templates::HTMLSafeString] string containing the page's full HTML.
56
- def render
57
- layout_template = Brut.container.layout_locator.locate(self.layout).
58
- then { |layout_erb_file| Brut::FrontEnd::Template.new(layout_erb_file) }
59
-
60
- template = Brut.container.page_locator.locate(self.template_name).
61
- then { |erb_file| Brut::FrontEnd::Template.new(erb_file) }
62
-
63
- Brut.container.instrumentation.add_event("templates found", layout: layout_template.template_file_path, page: template.template_file_path)
64
-
65
- page = template.render_template(self).html_safe!
66
- layout_template.render_template(self) do
67
- page
55
+ def view_template
56
+ with_layout do
57
+ page_template
68
58
  end
69
59
  end
70
60
 
61
+
71
62
  # @return [String] name of this page for use in debugging or for whatever reason you may want to dynamically refer to the page's name. The default value is the class name.
72
63
  def self.page_name = self.name
73
64
 
@@ -77,10 +68,6 @@ class Brut::FrontEnd::Page < Brut::FrontEnd::Component
77
68
  # @!visibility private
78
69
  def component_name = raise Brut::Framework::Errors::Bug,"#{self.class} is not a component"
79
70
 
80
- private
81
-
82
- def template_name = RichString.new(self.class.name).underscorized.to_s.gsub(/^pages\//,"")
83
-
84
71
  end
85
72
 
86
73
  # Holds pages included with the Brut framework
@@ -8,6 +8,19 @@
8
8
  # and create an initializer for it that accepts the `clock:` keyword argument, the managed instance of {Clock} will be passed into it
9
9
  # when Brut creates an instance of the class.
10
10
  class Brut::FrontEnd::RequestContext
11
+
12
+ def self.current
13
+ Thread.current.thread_variable_get(:request_context)
14
+ end
15
+
16
+ # Create an instance of klass injected with the request context.
17
+ def self.inject(klass, request_params: nil)
18
+ self.current.then { |request_context|
19
+ request_context.as_constructor_args(klass,request_params:)
20
+ }.then { |constructor_args|
21
+ klass.new(**constructor_args)
22
+ }
23
+ end
11
24
  # Create a new RequestContext based on some of the information provided by Rack
12
25
  #
13
26
  # @param [Hash] env the Rack `env` object, as available to any middleware
@@ -177,6 +190,8 @@ private
177
190
  args[name] = route
178
191
  elsif !request_params.nil? && (request_params[name.to_s] || request_params[name.to_sym])
179
192
  args[name] = RichString.new(request_params[name.to_s] || request_params[name.to_sym]).to_s_or_nil
193
+ elsif name == :raw_params
194
+ args[name] = request_params || {}
180
195
  elsif type == :keyreq
181
196
  request_params_message = if request_params.nil?
182
197
  "no request params provied"
@@ -1,4 +1,5 @@
1
1
  require "uri"
2
+ require "phlex"
2
3
 
3
4
  # Holds the registered routes for this app.
4
5
  class Brut::FrontEnd::Routing
@@ -218,11 +219,11 @@ private
218
219
  end
219
220
  uri = URI(joined_path)
220
221
  uri.query = URI.encode_www_form(query_string_params)
221
- uri
222
+ uri.extend(Phlex::SGML::SafeObject)
222
223
  end
223
224
 
224
225
  def url(**query_string_params)
225
- request_context = Thread.current.thread_variable_get(:request_context)
226
+ request_context = Brut::FrontEnd::RequestContext.current
226
227
  path = self.path(**query_string_params)
227
228
  host = if request_context
228
229
  request_context[:host]
@@ -0,0 +1,41 @@
1
+ # In Brut, the _front end_ is considered anything that interacts directly with a web browser or HTTP. This includes rendering HTML,
2
+ # managing JavaScript and CSS, and processing form submissions. It contrasts to {Brut::BackEnd}, which handles the business logic
3
+ # and database.
4
+ #
5
+ # You {Brut::App} defines pages, forms, and actions. A page is backed by a subclass of {Brut::FrontEnd::Page}, which provides
6
+ # dynamic data for rendering. A page can reference {Brut::FrontEnd::Component} subclasses to allow functional decomposition of front
7
+ # end logic and markup, as well as re-use. Both pages and components have ERB files that describe the HTML to be rendered.
8
+ #
9
+ # A {Brut::FrontEnd::Form} subclass defines a form that a browser will submit to your app. That
10
+ # submission is processed by a {Brut::FrontEnd::Handler} subclass. Handlers can also respond to other HTTP requests.
11
+ #
12
+ # In addition to responding to requests, you can subclass {Brut::FrontEnd::RouteHook} or {Brut::FrontEnd::Middleware} to perform
13
+ # further manipulation of the request.
14
+ #
15
+ # The entire front-end is based on Rack, so you should be able to achieve anything you need to.
16
+ module Brut::FrontEnd
17
+ autoload(:AssetMetadata, "brut/front_end/asset_metadata")
18
+ autoload(:AssetPathResolver, "brut/front_end/asset_path_resolver")
19
+ autoload(:Component, "brut/front_end/component")
20
+ autoload(:Components, "brut/front_end/component")
21
+ autoload(:Download, "brut/front_end/download")
22
+ autoload(:Flash, "brut/front_end/flash")
23
+ autoload(:Form, "brut/front_end/form")
24
+ autoload(:GenericResponse, "brut/front_end/generic_response")
25
+ autoload(:Handler, "brut/front_end/handler")
26
+ autoload(:Handlers, "brut/front_end/handler")
27
+ autoload(:HandlingResults, "brut/front_end/handling_results")
28
+ autoload(:HttpMethod, "brut/front_end/http_method")
29
+ autoload(:HttpStatus, "brut/front_end/http_status")
30
+ autoload(:InlineSvgLocator, "brut/front_end/inline_svg_locator")
31
+ autoload(:Layout, "brut/front_end/layout")
32
+ autoload(:Middleware, "brut/front_end/middleware")
33
+ autoload(:Middlewares, "brut/front_end/middleware")
34
+ autoload(:Page, "brut/front_end/page")
35
+ autoload(:Pages, "brut/front_end/page")
36
+ autoload(:RequestContext, "brut/front_end/request_context")
37
+ autoload(:RouteHook, "brut/front_end/route_hook")
38
+ autoload(:RouteHooks, "brut/front_end/route_hook")
39
+ autoload(:Routing, "brut/front_end/routing")
40
+ autoload(:Session, "brut/front_end/session")
41
+ end
@@ -1,6 +1,11 @@
1
- # Interface for translations. This is prefered over using Ruby's I18n directly.
2
- # This is intended to be mixed-in to any class that requires this, so that you can more
3
- # expediently access the `t` method.
1
+ # Interface for translations, preferred over Ruby's I18n classes. Note that this is a
2
+ # base module and not intended to be directly used in your classes. Include one of
3
+ # the other modules in this namespace:
4
+ #
5
+ # * {Brut::I18n::ForHTML} for components or pages, or anything use Phlex
6
+ # * {Brut::I18n::ForCLI} for CLI apps
7
+ # * {Brut::I18n::ForBackEnd} for back-end classes that aren't generating HTML
8
+ #
4
9
  module Brut::I18n::BaseMethods
5
10
 
6
11
  # Access a translation and insert interpolated elemens as needed. This will use the provided key to determine
@@ -101,7 +106,7 @@ module Brut::I18n::BaseMethods
101
106
  # }
102
107
  # # in your code for HomePage
103
108
  # t(page: [ :captions, :new ]) # => New Widgets
104
- def t(key=:look_in_rest,**rest)
109
+ def t(key=:look_in_rest,**rest,&block)
105
110
  if key == :look_in_rest
106
111
 
107
112
  page = rest.delete(:page)
@@ -126,13 +131,14 @@ module Brut::I18n::BaseMethods
126
131
  key = Array(key).join('.')
127
132
  key = [key,"general.#{key}"]
128
133
  end
129
- if block_given?
134
+ if !block.nil?
130
135
  if rest[:block]
131
136
  raise ArgumentError,"t was given a block and a block: param. You can't do both "
132
137
  end
133
- rest[:block] = html_safe(yield.to_s.strip)
138
+ block_contents = safe(capture(&block))
139
+ rest[:block] = block_contents
134
140
  end
135
- html_safe(t_direct(key,**rest))
141
+ t_direct(key,**rest)
136
142
  rescue I18n::MissingInterpolationArgument => ex
137
143
  if ex.key.to_s == "block"
138
144
  raise ArgumentError,"One of the keys #{key.join(", ")} contained a %{block} interpolation value: '#{ex.string}'. This means you must use t_html *and* yield a block to it"
@@ -168,7 +174,7 @@ module Brut::I18n::BaseMethods
168
174
  }
169
175
  escaped_interpolated_values = interpolated_values.map { |key,value|
170
176
  if value.kind_of?(String)
171
- [ key, Brut::FrontEnd::Template.escape_html(value) ]
177
+ [ key, CGI.escapeHTML(value) ]
172
178
  else
173
179
  [ key, value ]
174
180
  end
@@ -0,0 +1,5 @@
1
+ module Brut::I18n::ForBackEnd
2
+ include Brut::I18n::BaseMethods
3
+ def safe(string) = string
4
+ def capture(&block) = block.()
5
+ end
@@ -1,4 +1,5 @@
1
1
  module Brut::I18n::ForCLI
2
2
  include Brut::I18n::BaseMethods
3
- def html_safe(string) = string
3
+ def safe(string) = string
4
+ def capture(&block) = block.()
4
5
  end
@@ -1,4 +1,12 @@
1
+ # I18n for components or pages, which are assumed to be Phlex components.
2
+ # To use this outside of a Phlex context, you must define these two
3
+ # methods to ensure proper HTML escaping happens:
4
+ #
5
+ # * `safe` to accept a string and return a string.
6
+ # * `capture` to accept a block and return its contents as a string.
1
7
  module Brut::I18n::ForHTML
2
8
  include Brut::I18n::BaseMethods
3
- def html_safe(string) = Brut::FrontEnd::Templates::HTMLSafeString.from_string(string)
9
+ def t(...)
10
+ safe(super)
11
+ end
4
12
  end
data/lib/brut/i18n.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # I18n holds all the code useful for translating and localizing information. It's based on Ruby's I18n.
2
2
  module Brut::I18n
3
3
  autoload(:BaseMethods, "brut/i18n/base_methods")
4
+ autoload(:ForBackEnd, "brut/i18n/for_back_end")
4
5
  autoload(:ForCLI, "brut/i18n/for_cli")
5
6
  autoload(:ForHTML, "brut/i18n/for_html")
6
7
  autoload(:HTTPAcceptLanguage, "brut/i18n/http_accept_language")
@@ -77,15 +77,16 @@ module Brut::SinatraHelpers
77
77
 
78
78
  Brut.container.instrumentation.span(page_class.name) do |span|
79
79
  span.add_prefixed_attributes("brut", type: :page, class: page_class)
80
- request_context = Thread.current.thread_variable_get(:request_context)
81
- constructor_args = request_context.as_constructor_args(
80
+ constructor_args = Brut::FrontEnd::RequestContext.current.as_constructor_args(
82
81
  page_class,
83
82
  request_params: params,
84
83
  route: brut_route,
85
84
  )
86
85
  span.add_prefixed_attributes("brut.initializer.args", constructor_args.map { |k,v| [k.to_s,v.class.name] }.to_h)
87
86
  page_instance = page_class.new(**constructor_args)
87
+
88
88
  result = page_instance.handle!
89
+
89
90
  span.add_prefixed_attributes("brut", result_class: result.class)
90
91
  case result
91
92
  in URI => uri
@@ -177,7 +178,6 @@ module Brut::SinatraHelpers
177
178
  form_class: form_class,
178
179
  )
179
180
 
180
- request_context = Thread.current.thread_variable_get(:request_context)
181
181
  handler = handler_class.new
182
182
  form = if form_class.nil?
183
183
  nil
@@ -185,7 +185,7 @@ module Brut::SinatraHelpers
185
185
  form_class.new(params: params)
186
186
  end
187
187
 
188
- process_args = request_context.as_method_args(handler,:handle,request_params: params,form: form,route:brut_route)
188
+ process_args = Brut::FrontEnd::RequestContext.current.as_method_args(handler,:handle,request_params: params,form: form,route:brut_route)
189
189
 
190
190
  result = handler.handle!(**process_args)
191
191
 
@@ -193,16 +193,23 @@ module Brut::SinatraHelpers
193
193
  in URI => uri
194
194
  redirect to(uri.to_s)
195
195
  in Brut::FrontEnd::Component => component_instance
196
- render_html(component_instance).to_s
197
- in [ Brut::FrontEnd::Component => component_instance, Brut::FrontEnd::HttpStatus => http_status ]
196
+ component_instance.call.to_s
197
+ in [
198
+ Brut::FrontEnd::Component => component_instance,
199
+ Brut::FrontEnd::HttpStatus => http_status,
200
+ ]
201
+
198
202
  [
199
203
  http_status.to_i,
200
- render_html(component_instance).to_s,
204
+ component_instance.call.to_s,
201
205
  ]
206
+
202
207
  in Brut::FrontEnd::HttpStatus => http_status
203
208
  http_status.to_i
204
209
  in Brut::FrontEnd::Download => download
205
210
  [ 200, download.headers, download.data ]
211
+ in Brut::FrontEnd::GenericResponse => response
212
+ response.to_ary
206
213
  else
207
214
  raise NoMatchingPatternError, "Result from #{handler.class}'s handle! method was a #{result.class}, which cannot be used to understand the response to generate"
208
215
  end
@@ -8,7 +8,7 @@ module Brut::SpecSupport::ComponentSupport
8
8
  include Brut::SpecSupport::FlashSupport
9
9
  include Brut::SpecSupport::SessionSupport
10
10
  include Brut::SpecSupport::ClockSupport
11
- include Brut::I18n::ForHTML
11
+ include Brut::I18n::BaseMethods
12
12
 
13
13
  # Render a component into its text representation. This mimics what happens when a component is used
14
14
  # inside a template. You typically don't want this, but should use {#render_and_parse}, since that will
@@ -20,8 +20,13 @@ module Brut::SpecSupport::ComponentSupport
20
20
  end
21
21
  component.handle!
22
22
  else
23
- component.yielded_block = block
24
- component.render
23
+ if block.nil?
24
+ component.call
25
+ else
26
+ component.call do
27
+ component.raw(component.safe(block.()))
28
+ end
29
+ end
25
30
  end
26
31
  end
27
32
 
@@ -41,7 +46,7 @@ module Brut::SpecSupport::ComponentSupport
41
46
  # @return [Brut::SpecSupport::EnhancedNode] a wrapper around a Nokogiri node to provide convienience methods.
42
47
  def render_and_parse(component,&block)
43
48
  rendered_text = render(component,&block)
44
- if !rendered_text.kind_of?(String) && !rendered_text.kind_of?(Brut::FrontEnd::Templates::HTMLSafeString)
49
+ if !rendered_text.kind_of?(String)
45
50
  if rendered_text.kind_of?(URI::Generic)
46
51
  raise "#{component.class} redirected to #{rendered_text} instead of rendering"
47
52
  else
@@ -80,9 +85,4 @@ module Brut::SpecSupport::ComponentSupport
80
85
  def routing_for(klass,**args)
81
86
  Brut.container.routing.path(klass,**args)
82
87
  end
83
-
84
- # Escape HTML using the same code Brut uses for rendering templates.
85
- def escape_html(...)
86
- Brut::FrontEnd::Templates::EscapableFilter.escape_html(...)
87
- end
88
88
  end
@@ -0,0 +1,4 @@
1
+ # Convienience methods for writing E2E tests
2
+ module Brut::SpecSupport::E2eSupport
3
+ include Brut::I18n::BaseMethods
4
+ end
@@ -1,5 +1,10 @@
1
1
  RSpec::Matchers.define :have_i18n_string do |key,**args|
2
2
  include Brut::I18n::ForHTML
3
+
4
+ # XXX: Figure out how to not have to do this
5
+ def safe(x) = x
6
+ def capture(&block) = block.()
7
+
3
8
  match do |nokogiri_node|
4
9
 
5
10
  text = nokogiri_node.text.strip
@@ -80,6 +80,7 @@ class Brut::SpecSupport::RSpecSetup
80
80
  @config.include Brut::SpecSupport::GeneralSupport
81
81
  @config.include Brut::SpecSupport::ComponentSupport, component: true
82
82
  @config.include Brut::SpecSupport::HandlerSupport, handler: true
83
+ @config.include Brut::SpecSupport::E2eSupport, e2e: true
83
84
  @config.include Playwright::Test::Matchers, e2e: true
84
85
 
85
86
  @config.around do |example|
@@ -5,11 +5,12 @@ module Brut
5
5
  module SpecSupport
6
6
  end
7
7
  end
8
- require_relative "spec_support/matcher"
9
8
  require_relative "spec_support/component_support"
10
- require_relative "spec_support/handler_support"
11
- require_relative "spec_support/general_support"
9
+ require_relative "spec_support/e2e_support"
12
10
  require_relative "spec_support/e2e_test_server"
11
+ require_relative "spec_support/general_support"
12
+ require_relative "spec_support/handler_support"
13
+ require_relative "spec_support/matcher"
13
14
  require_relative "spec_support/rspec_setup"
14
15
  require_relative "factory_bot"
15
16
  # Convention here is different. We don't want to autoload
data/lib/brut/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Brut
2
2
  # @!visibility private
3
- VERSION = "0.0.12"
3
+ VERSION = "0.0.20"
4
4
  end
data/lib/brut.rb CHANGED
@@ -9,51 +9,8 @@ require_relative "brut/framework"
9
9
  #
10
10
  # Have fun!
11
11
  module Brut
12
- # In Brut, the _front end_ is considered anything that interacts directly with a web browser or HTTP. This includes rendering HTML,
13
- # managing JavaScript and CSS, and processing form submissions. It contrasts to {Brut::BackEnd}, which handles the business logic
14
- # and database.
15
- #
16
- # You {Brut::App} defines pages, forms, and actions. A page is backed by a subclass of {Brut::FrontEnd::Page}, which provides
17
- # dynamic data for rendering. A page can reference {Brut::FrontEnd::Component} subclasses to allow functional decomposition of front
18
- # end logic and markup, as well as re-use. Both pages and components have ERB files that describe the HTML to be rendered.
19
- #
20
- # A {Brut::FrontEnd::Form} subclass defines a form that a browser will submit to your app. That
21
- # submission is processed by a {Brut::FrontEnd::Handler} subclass. Handlers can also respond to other HTTP requests.
22
- #
23
- # In addition to responding to requests, you can subclass {Brut::FrontEnd::RouteHook} or {Brut::FrontEnd::Middleware} to perform
24
- # further manipulation of the request.
25
- #
26
- # The entire front-end is based on Rack, so you should be able to achieve anything you need to.
27
- module FrontEnd
28
- autoload(:AssetMetadata, "brut/front_end/asset_metadata")
29
- autoload(:Component, "brut/front_end/component")
30
- autoload(:Components, "brut/front_end/component")
31
- autoload(:Download, "brut/front_end/download")
32
- autoload(:Flash, "brut/front_end/flash")
33
- autoload(:Form, "brut/front_end/form")
34
- autoload(:Handler, "brut/front_end/handler")
35
- autoload(:Handlers, "brut/front_end/handler")
36
- autoload(:HandlingResults, "brut/front_end/handling_results")
37
- autoload(:HttpMethod, "brut/front_end/http_method")
38
- autoload(:HttpStatus, "brut/front_end/http_status")
39
- autoload(:Middleware, "brut/front_end/middleware")
40
- autoload(:Middlewares, "brut/front_end/middleware")
41
- autoload(:Page, "brut/front_end/page")
42
- autoload(:Pages, "brut/front_end/page")
43
- autoload(:RequestContext, "brut/front_end/request_context")
44
- autoload(:RouteHook, "brut/front_end/route_hook")
45
- autoload(:RouteHooks, "brut/front_end/route_hook")
46
- autoload(:Routing, "brut/front_end/routing")
47
- autoload(:Session, "brut/front_end/session")
48
- end
49
- # The _back end_ of a Brut app is where your app's business logic and database are managed. While the bulk of your Brut app's code
50
- # will be in the back end, Brut is far less prescriptive about how to manage that than it is the front end.
51
- module BackEnd
52
- autoload(:Validators, "brut/back_end/validator")
53
- autoload(:Sidekiq, "brut/back_end/sidekiq")
54
- # Do not put SeedData here - it must be loaded only when needed
55
- end
56
- # I18n is where internationalization and localization support lives.
12
+ autoload(:FrontEnd, "brut/front_end")
13
+ autoload(:BackEnd, "brut/back_end")
57
14
  autoload(:I18n, "brut/i18n")
58
15
  autoload(:Instrumentation,"brut/instrumentation")
59
16
  autoload(:SinatraHelpers, "brut/sinatra_helpers")
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brut
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.12
4
+ version: 0.0.20
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Bryant Copeland
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-04-05 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: irb
@@ -80,7 +80,7 @@ dependencies:
80
80
  - !ruby/object:Gem::Version
81
81
  version: '0'
82
82
  - !ruby/object:Gem::Dependency
83
- name: prism
83
+ name: phlex
84
84
  requirement: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - ">="
@@ -94,7 +94,7 @@ dependencies:
94
94
  - !ruby/object:Gem::Version
95
95
  version: '0'
96
96
  - !ruby/object:Gem::Dependency
97
- name: rack-protection
97
+ name: prism
98
98
  requirement: !ruby/object:Gem::Requirement
99
99
  requirements:
100
100
  - - ">="
@@ -108,7 +108,7 @@ dependencies:
108
108
  - !ruby/object:Gem::Version
109
109
  version: '0'
110
110
  - !ruby/object:Gem::Dependency
111
- name: rackup
111
+ name: rack-protection
112
112
  requirement: !ruby/object:Gem::Requirement
113
113
  requirements:
114
114
  - - ">="
@@ -122,7 +122,7 @@ dependencies:
122
122
  - !ruby/object:Gem::Version
123
123
  version: '0'
124
124
  - !ruby/object:Gem::Dependency
125
- name: rexml
125
+ name: rackup
126
126
  requirement: !ruby/object:Gem::Requirement
127
127
  requirements:
128
128
  - - ">="
@@ -177,34 +177,6 @@ dependencies:
177
177
  - - ">="
178
178
  - !ruby/object:Gem::Version
179
179
  version: '0'
180
- - !ruby/object:Gem::Dependency
181
- name: temple
182
- requirement: !ruby/object:Gem::Requirement
183
- requirements:
184
- - - ">="
185
- - !ruby/object:Gem::Version
186
- version: '0'
187
- type: :runtime
188
- prerelease: false
189
- version_requirements: !ruby/object:Gem::Requirement
190
- requirements:
191
- - - ">="
192
- - !ruby/object:Gem::Version
193
- version: '0'
194
- - !ruby/object:Gem::Dependency
195
- name: tilt
196
- requirement: !ruby/object:Gem::Requirement
197
- requirements:
198
- - - ">="
199
- - !ruby/object:Gem::Version
200
- version: '0'
201
- type: :runtime
202
- prerelease: false
203
- version_requirements: !ruby/object:Gem::Requirement
204
- requirements:
205
- - - ">="
206
- - !ruby/object:Gem::Version
207
- version: '0'
208
180
  - !ruby/object:Gem::Dependency
209
181
  name: tzinfo
210
182
  requirement: !ruby/object:Gem::Requirement
@@ -454,6 +426,7 @@ files:
454
426
  - dx/start
455
427
  - dx/stop
456
428
  - lib/brut.rb
429
+ - lib/brut/back_end.rb
457
430
  - lib/brut/back_end/seed_data.rb
458
431
  - lib/brut/back_end/sidekiq.rb
459
432
  - lib/brut/back_end/sidekiq/middlewares.rb
@@ -491,7 +464,9 @@ files:
491
464
  - lib/brut/framework/mcp.rb
492
465
  - lib/brut/framework/patch_semantic_logger.rb
493
466
  - lib/brut/framework/project_environment.rb
467
+ - lib/brut/front_end.rb
494
468
  - lib/brut/front_end/asset_metadata.rb
469
+ - lib/brut/front_end/asset_path_resolver.rb
495
470
  - lib/brut/front_end/component.rb
496
471
  - lib/brut/front_end/components/constraint_violations.rb
497
472
  - lib/brut/front_end/components/form_tag.rb
@@ -504,7 +479,7 @@ files:
504
479
  - lib/brut/front_end/components/inputs/textarea.rb
505
480
  - lib/brut/front_end/components/locale_detection.rb
506
481
  - lib/brut/front_end/components/page_identifier.rb
507
- - lib/brut/front_end/components/time.rb
482
+ - lib/brut/front_end/components/time_tag.rb
508
483
  - lib/brut/front_end/components/traceparent.rb
509
484
  - lib/brut/front_end/download.rb
510
485
  - lib/brut/front_end/flash.rb
@@ -518,6 +493,7 @@ files:
518
493
  - lib/brut/front_end/forms/select_input.rb
519
494
  - lib/brut/front_end/forms/select_input_definition.rb
520
495
  - lib/brut/front_end/forms/validity_state.rb
496
+ - lib/brut/front_end/generic_response.rb
521
497
  - lib/brut/front_end/handler.rb
522
498
  - lib/brut/front_end/handlers/csp_reporting_handler.rb
523
499
  - lib/brut/front_end/handlers/instrumentation_handler.rb
@@ -526,6 +502,8 @@ files:
526
502
  - lib/brut/front_end/handling_results.rb
527
503
  - lib/brut/front_end/http_method.rb
528
504
  - lib/brut/front_end/http_status.rb
505
+ - lib/brut/front_end/inline_svg_locator.rb
506
+ - lib/brut/front_end/layout.rb
529
507
  - lib/brut/front_end/layouts/_internal.html.erb
530
508
  - lib/brut/front_end/middleware.rb
531
509
  - lib/brut/front_end/middlewares/annotate_brut_owned_paths.rb
@@ -544,15 +522,9 @@ files:
544
522
  - lib/brut/front_end/route_hooks/setup_request_context.rb
545
523
  - lib/brut/front_end/routing.rb
546
524
  - lib/brut/front_end/session.rb
547
- - lib/brut/front_end/template.rb
548
- - lib/brut/front_end/templates/block_filter.rb
549
- - lib/brut/front_end/templates/erb_engine.rb
550
- - lib/brut/front_end/templates/erb_parser.rb
551
- - lib/brut/front_end/templates/escapable_filter.rb
552
- - lib/brut/front_end/templates/html_safe_string.rb
553
- - lib/brut/front_end/templates/locator.rb
554
525
  - lib/brut/i18n.rb
555
526
  - lib/brut/i18n/base_methods.rb
527
+ - lib/brut/i18n/for_back_end.rb
556
528
  - lib/brut/i18n/for_cli.rb
557
529
  - lib/brut/i18n/for_html.rb
558
530
  - lib/brut/i18n/http_accept_language.rb
@@ -564,6 +536,7 @@ files:
564
536
  - lib/brut/spec_support.rb
565
537
  - lib/brut/spec_support/clock_support.rb
566
538
  - lib/brut/spec_support/component_support.rb
539
+ - lib/brut/spec_support/e2e_support.rb
567
540
  - lib/brut/spec_support/e2e_test_server.rb
568
541
  - lib/brut/spec_support/enhanced_node.rb
569
542
  - lib/brut/spec_support/flash_support.rb
@@ -610,7 +583,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
610
583
  - !ruby/object:Gem::Version
611
584
  version: '0'
612
585
  requirements: []
613
- rubygems_version: 3.6.6
586
+ rubygems_version: 3.6.7
614
587
  specification_version: 4
615
588
  summary: NOT YET RELEASED - Web Framework Built around Ruby, Web Standards, Simplicity,
616
589
  and Object-Orientation