brut 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +6 -0
- data/Gemfile.lock +66 -1
- data/README.md +36 -0
- data/Rakefile +22 -0
- data/brut.gemspec +7 -0
- data/doc-src/architecture.md +102 -0
- data/doc-src/assets.md +98 -0
- data/doc-src/forms.md +214 -0
- data/doc-src/handlers.md +83 -0
- data/doc-src/javascript.md +265 -0
- data/doc-src/keyword-injection.md +183 -0
- data/doc-src/pages.md +210 -0
- data/doc-src/route-hooks.md +59 -0
- data/docs-todo.md +32 -0
- data/lib/brut/back_end/seed_data.rb +5 -1
- data/lib/brut/back_end/validator.rb +1 -1
- data/lib/brut/back_end/validators/form_validator.rb +31 -6
- data/lib/brut/cli/app.rb +100 -4
- data/lib/brut/cli/app_runner.rb +38 -5
- data/lib/brut/cli/apps/build_assets.rb +4 -6
- data/lib/brut/cli/apps/db.rb +2 -7
- data/lib/brut/cli/apps/scaffold.rb +413 -7
- data/lib/brut/cli/apps/test.rb +14 -1
- data/lib/brut/cli/command.rb +141 -6
- data/lib/brut/cli/error.rb +30 -3
- data/lib/brut/cli/execution_results.rb +44 -6
- data/lib/brut/cli/executor.rb +21 -1
- data/lib/brut/cli/options.rb +29 -2
- data/lib/brut/cli/output.rb +47 -0
- data/lib/brut/cli.rb +26 -0
- data/lib/brut/factory_bot.rb +2 -0
- data/lib/brut/framework/app.rb +38 -5
- data/lib/brut/framework/config.rb +97 -54
- data/lib/brut/framework/container.rb +97 -33
- data/lib/brut/framework/errors/abstract_method.rb +3 -7
- data/lib/brut/framework/errors/missing_parameter.rb +12 -0
- data/lib/brut/framework/errors/no_class_for_path.rb +25 -0
- data/lib/brut/framework/errors/not_found.rb +12 -2
- data/lib/brut/framework/errors/not_implemented.rb +14 -0
- data/lib/brut/framework/errors.rb +18 -0
- data/lib/brut/framework/fussy_type_enforcement.rb +17 -12
- data/lib/brut/framework/mcp.rb +106 -49
- data/lib/brut/framework/project_environment.rb +9 -0
- data/lib/brut/framework.rb +1 -0
- data/lib/brut/front_end/asset_metadata.rb +7 -1
- data/lib/brut/front_end/component.rb +129 -38
- data/lib/brut/front_end/components/constraint_violations.rb +57 -0
- data/lib/brut/front_end/components/form_tag.rb +23 -32
- data/lib/brut/front_end/components/i18n_translations.rb +34 -1
- data/lib/brut/front_end/components/input.rb +3 -0
- data/lib/brut/front_end/components/inputs/csrf_token.rb +2 -0
- data/lib/brut/front_end/components/inputs/radio_button.rb +41 -0
- data/lib/brut/front_end/components/inputs/select.rb +26 -2
- data/lib/brut/front_end/components/inputs/text_field.rb +27 -5
- data/lib/brut/front_end/components/inputs/textarea.rb +24 -4
- data/lib/brut/front_end/components/locale_detection.rb +8 -1
- data/lib/brut/front_end/components/page_identifier.rb +2 -0
- data/lib/brut/front_end/components/time.rb +95 -0
- data/lib/brut/front_end/components/traceparent.rb +22 -0
- data/lib/brut/front_end/download.rb +11 -0
- data/lib/brut/front_end/flash.rb +32 -0
- data/lib/brut/front_end/form.rb +109 -106
- data/lib/brut/front_end/forms/constraint_violation.rb +16 -11
- data/lib/brut/front_end/forms/input.rb +30 -42
- data/lib/brut/front_end/forms/input_declarations.rb +90 -0
- data/lib/brut/front_end/forms/input_definition.rb +45 -30
- data/lib/brut/front_end/forms/radio_button_group_input.rb +46 -0
- data/lib/brut/front_end/forms/radio_button_group_input_definition.rb +29 -0
- data/lib/brut/front_end/forms/select_input.rb +47 -0
- data/lib/brut/front_end/forms/select_input_definition.rb +27 -0
- data/lib/brut/front_end/forms/validity_state.rb +23 -9
- data/lib/brut/front_end/handler.rb +27 -8
- data/lib/brut/front_end/handlers/csp_reporting_handler.rb +4 -2
- data/lib/brut/front_end/handlers/instrumentation_handler.rb +99 -0
- data/lib/brut/front_end/handlers/locale_detection_handler.rb +9 -4
- data/lib/brut/front_end/handlers/missing_handler.rb +9 -0
- data/lib/brut/front_end/handling_results.rb +14 -4
- data/lib/brut/front_end/http_method.rb +13 -1
- data/lib/brut/front_end/http_status.rb +10 -0
- data/lib/brut/front_end/layouts/_internal.html.erb +68 -0
- data/lib/brut/front_end/middleware.rb +5 -0
- data/lib/brut/front_end/middlewares/annotate_brut_owned_paths.rb +15 -0
- data/lib/brut/front_end/middlewares/favicon.rb +16 -0
- data/lib/brut/front_end/middlewares/open_telemetry_span.rb +12 -0
- data/lib/brut/front_end/middlewares/reload_app.rb +27 -9
- data/lib/brut/front_end/page.rb +50 -11
- data/lib/brut/front_end/pages/_missing_page.html.erb +17 -0
- data/lib/brut/front_end/pages/missing_page.rb +36 -0
- data/lib/brut/front_end/request_context.rb +117 -8
- data/lib/brut/front_end/route_hook.rb +43 -1
- data/lib/brut/front_end/route_hooks/age_flash.rb +3 -2
- data/lib/brut/front_end/route_hooks/csp_no_inline_scripts.rb +8 -0
- data/lib/brut/front_end/route_hooks/csp_no_inline_styles_or_scripts.rb +18 -10
- data/lib/brut/front_end/route_hooks/locale_detection.rb +11 -5
- data/lib/brut/front_end/route_hooks/setup_request_context.rb +7 -4
- data/lib/brut/front_end/routing.rb +138 -31
- data/lib/brut/front_end/session.rb +86 -7
- data/lib/brut/front_end/template.rb +17 -2
- data/lib/brut/front_end/templates/block_filter.rb +4 -3
- data/lib/brut/front_end/templates/erb_parser.rb +1 -1
- data/lib/brut/front_end/templates/escapable_filter.rb +2 -0
- data/lib/brut/front_end/templates/html_safe_string.rb +30 -2
- data/lib/brut/front_end/templates/locator.rb +60 -0
- data/lib/brut/i18n/base_methods.rb +4 -0
- data/lib/brut/i18n.rb +1 -0
- data/lib/brut/instrumentation/logger_span_exporter.rb +75 -0
- data/lib/brut/instrumentation/open_telemetry.rb +107 -0
- data/lib/brut/instrumentation.rb +4 -6
- data/lib/brut/junk_drawer.rb +54 -4
- data/lib/brut/sinatra_helpers.rb +42 -38
- data/lib/brut/spec_support/clock_support.rb +6 -0
- data/lib/brut/spec_support/component_support.rb +53 -26
- data/lib/brut/spec_support/e2e_test_server.rb +82 -0
- data/lib/brut/spec_support/enhanced_node.rb +45 -0
- data/lib/brut/spec_support/general_support.rb +14 -3
- data/lib/brut/spec_support/handler_support.rb +2 -0
- data/lib/brut/spec_support/matcher.rb +6 -3
- data/lib/brut/spec_support/matchers/be_page_for.rb +3 -2
- data/lib/brut/spec_support/matchers/have_constraint_violation.rb +22 -9
- data/lib/brut/spec_support/matchers/have_html_attribute.rb +9 -2
- data/lib/brut/spec_support/matchers/have_i18n_string.rb +24 -0
- data/lib/brut/spec_support/matchers/have_link_to.rb +14 -0
- data/lib/brut/spec_support/matchers/have_redirected_to.rb +30 -0
- data/lib/brut/spec_support/matchers/have_rendered.rb +4 -11
- data/lib/brut/spec_support/matchers/have_returned_http_status.rb +16 -8
- data/lib/brut/spec_support/rspec_setup.rb +182 -0
- data/lib/brut/spec_support.rb +8 -3
- data/lib/brut/version.rb +2 -1
- data/lib/brut.rb +28 -5
- data/lib/sequel/extensions/brut_instrumentation.rb +5 -27
- data/lib/sequel/extensions/brut_migrations.rb +18 -8
- data/lib/sequel/plugins/created_at.rb +2 -0
- data/lib/sequel/plugins/external_id.rb +39 -1
- data/lib/sequel/plugins/find_bang.rb +4 -1
- metadata +140 -13
- data/lib/brut/back_end/action.rb +0 -3
- data/lib/brut/back_end/result.rb +0 -46
- data/lib/brut/front_end/components/timestamp.rb +0 -33
- data/lib/brut/instrumentation/basic.rb +0 -66
- data/lib/brut/instrumentation/event.rb +0 -19
- data/lib/brut/instrumentation/http_event.rb +0 -5
- data/lib/brut/instrumentation/subscriber.rb +0 -41
@@ -1,19 +1,51 @@
|
|
1
1
|
module Sequel
|
2
2
|
module Plugins
|
3
|
+
# Configures models with an external id that can be safely shared publicly and safely rotated. The external
|
4
|
+
# id is random, however it is prefixed with configurable strings that can indicate what type of model it represents.
|
5
|
+
# This disambiguates ids when shared pubnlically or in internal tooling.
|
6
|
+
#
|
7
|
+
# This extension accepts a configuration option `global_prefix:` that is a string prepended to all external IDs. This ensures
|
8
|
+
# that your app's IDs clearly come from your app and not some other app that may be using external ids.
|
9
|
+
#
|
10
|
+
# To use external ids you must then call {ClassMethods#has_external_id} in your model. This method accepts a string which is
|
11
|
+
# appended to the global prefix. This is then *prepended* to a unique identifier. The per-model external id prefix should
|
12
|
+
# indicate the type of the model. Note that it's not intended to be used programmatically—it's only for humans to quickly see
|
13
|
+
# what type of thing an identifier represents.
|
14
|
+
#
|
15
|
+
# When {ClassMethods#has_external_id} is called on your model, the column `external_id` will be set on save if it has no value.
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
# class DB::Widget < AppDataModel
|
19
|
+
# has_external_id "wg"
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# Sequel::Model.plugin :external_id, global_prefix: "my"
|
23
|
+
#
|
24
|
+
# widget = DB::Widget.new(name: "flux capacitor")
|
25
|
+
# widget.external_id # => mywg_43792834f9c3a7
|
3
26
|
module ExternalId
|
27
|
+
# @!visibility private
|
4
28
|
def self.apply(model,*args,&block)
|
5
29
|
@global_prefix = (args.first || {})[:global_prefix]
|
6
30
|
end
|
31
|
+
def self.global_prefix = @global_prefix
|
7
32
|
|
8
33
|
module ClassMethods
|
9
|
-
|
34
|
+
# @!visibility private
|
35
|
+
def global_prefix = Sequel::Plugins::ExternalId.global_prefix
|
36
|
+
# Called inside a model's body to indicate that this model has an `external_id` that this plugin should manage and what
|
37
|
+
# prefix should be used. Calling this will also alter {InstanceMethods#to_s} to include this id in the string representation.
|
38
|
+
#
|
39
|
+
# @param prefix [String] a short string identfying the type of this model. It will be prepended to your external_id.
|
10
40
|
def has_external_id(prefix)
|
11
41
|
global_prefix = find_global_prefix
|
12
42
|
@external_id_prefix = RichString.new("#{global_prefix}#{prefix}").to_s_or_nil
|
13
43
|
end
|
14
44
|
|
45
|
+
# @!visibility private
|
15
46
|
def external_id_prefix = @external_id_prefix
|
16
47
|
|
48
|
+
# @!visibility private
|
17
49
|
def find_global_prefix(receiver=self)
|
18
50
|
if receiver.respond_to?(:global_prefix)
|
19
51
|
if receiver.global_prefix.nil?
|
@@ -30,6 +62,7 @@ module Sequel
|
|
30
62
|
end
|
31
63
|
|
32
64
|
module InstanceMethods
|
65
|
+
# @!visibility private
|
33
66
|
def before_save
|
34
67
|
if self.class.external_id_prefix
|
35
68
|
if self.external_id.nil?
|
@@ -39,6 +72,11 @@ module Sequel
|
|
39
72
|
end
|
40
73
|
super
|
41
74
|
end
|
75
|
+
# Includes the external id in the super class' representation. This means you can include
|
76
|
+
# models in Log messages without having to explicitly fetch the id.
|
77
|
+
def to_s
|
78
|
+
super.to_s + "[external_id:#{self.external_id}]"
|
79
|
+
end
|
42
80
|
end
|
43
81
|
end
|
44
82
|
end
|
@@ -1,11 +1,14 @@
|
|
1
1
|
module Sequel
|
2
2
|
module Plugins
|
3
|
+
# Adds {ClassMethods#find!} to all models, which behaves as it does in Rails.
|
3
4
|
module FindBang
|
4
5
|
module ClassMethods
|
6
|
+
# Calls `first!`, but provides a more helpful error message when no records are found.
|
7
|
+
# @raise [Brut::Framework::Errors::NotFound]
|
5
8
|
def find!(**args)
|
6
9
|
self.first!(**args)
|
7
10
|
rescue Sequel::NoMatchingRow => ex
|
8
|
-
raise
|
11
|
+
raise Brut::Framework::Errors::NotFound.new(resource_name: self.name,search_terms: args.inspect,context: ex.message)
|
9
12
|
end
|
10
13
|
end
|
11
14
|
end
|
metadata
CHANGED
@@ -1,15 +1,28 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: brut
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Bryant Copeland
|
8
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-02-18 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: irb
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - ">="
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '0'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - ">="
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '0'
|
13
26
|
- !ruby/object:Gem::Dependency
|
14
27
|
name: dotenv
|
15
28
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,6 +65,20 @@ dependencies:
|
|
52
65
|
- - ">="
|
53
66
|
- !ruby/object:Gem::Version
|
54
67
|
version: '0'
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: concurrent-ruby
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
type: :runtime
|
76
|
+
prerelease: false
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
55
82
|
- !ruby/object:Gem::Dependency
|
56
83
|
name: faker
|
57
84
|
requirement: !ruby/object:Gem::Requirement
|
@@ -262,6 +289,34 @@ dependencies:
|
|
262
289
|
- - ">="
|
263
290
|
- !ruby/object:Gem::Version
|
264
291
|
version: '0'
|
292
|
+
- !ruby/object:Gem::Dependency
|
293
|
+
name: opentelemetry-sdk
|
294
|
+
requirement: !ruby/object:Gem::Requirement
|
295
|
+
requirements:
|
296
|
+
- - ">="
|
297
|
+
- !ruby/object:Gem::Version
|
298
|
+
version: '0'
|
299
|
+
type: :runtime
|
300
|
+
prerelease: false
|
301
|
+
version_requirements: !ruby/object:Gem::Requirement
|
302
|
+
requirements:
|
303
|
+
- - ">="
|
304
|
+
- !ruby/object:Gem::Version
|
305
|
+
version: '0'
|
306
|
+
- !ruby/object:Gem::Dependency
|
307
|
+
name: opentelemetry-exporter-otlp
|
308
|
+
requirement: !ruby/object:Gem::Requirement
|
309
|
+
requirements:
|
310
|
+
- - ">="
|
311
|
+
- !ruby/object:Gem::Version
|
312
|
+
version: '0'
|
313
|
+
type: :runtime
|
314
|
+
prerelease: false
|
315
|
+
version_requirements: !ruby/object:Gem::Requirement
|
316
|
+
requirements:
|
317
|
+
- - ">="
|
318
|
+
- !ruby/object:Gem::Version
|
319
|
+
version: '0'
|
265
320
|
- !ruby/object:Gem::Dependency
|
266
321
|
name: activesupport
|
267
322
|
requirement: !ruby/object:Gem::Requirement
|
@@ -318,6 +373,48 @@ dependencies:
|
|
318
373
|
- - ">="
|
319
374
|
- !ruby/object:Gem::Version
|
320
375
|
version: '0'
|
376
|
+
- !ruby/object:Gem::Dependency
|
377
|
+
name: yard
|
378
|
+
requirement: !ruby/object:Gem::Requirement
|
379
|
+
requirements:
|
380
|
+
- - ">="
|
381
|
+
- !ruby/object:Gem::Version
|
382
|
+
version: '0'
|
383
|
+
type: :development
|
384
|
+
prerelease: false
|
385
|
+
version_requirements: !ruby/object:Gem::Requirement
|
386
|
+
requirements:
|
387
|
+
- - ">="
|
388
|
+
- !ruby/object:Gem::Version
|
389
|
+
version: '0'
|
390
|
+
- !ruby/object:Gem::Dependency
|
391
|
+
name: rdiscount
|
392
|
+
requirement: !ruby/object:Gem::Requirement
|
393
|
+
requirements:
|
394
|
+
- - ">="
|
395
|
+
- !ruby/object:Gem::Version
|
396
|
+
version: '0'
|
397
|
+
type: :development
|
398
|
+
prerelease: false
|
399
|
+
version_requirements: !ruby/object:Gem::Requirement
|
400
|
+
requirements:
|
401
|
+
- - ">="
|
402
|
+
- !ruby/object:Gem::Version
|
403
|
+
version: '0'
|
404
|
+
- !ruby/object:Gem::Dependency
|
405
|
+
name: rdoc
|
406
|
+
requirement: !ruby/object:Gem::Requirement
|
407
|
+
requirements:
|
408
|
+
- - ">="
|
409
|
+
- !ruby/object:Gem::Version
|
410
|
+
version: '0'
|
411
|
+
type: :development
|
412
|
+
prerelease: false
|
413
|
+
version_requirements: !ruby/object:Gem::Requirement
|
414
|
+
requirements:
|
415
|
+
- - ">="
|
416
|
+
- !ruby/object:Gem::Version
|
417
|
+
version: '0'
|
321
418
|
description: NOT YET RELEASED - An opinionated web framework build on web standards
|
322
419
|
email:
|
323
420
|
- davec@thirdtank.com
|
@@ -337,7 +434,16 @@ files:
|
|
337
434
|
- bin/rake
|
338
435
|
- bin/setup
|
339
436
|
- brut.gemspec
|
437
|
+
- doc-src/architecture.md
|
438
|
+
- doc-src/assets.md
|
439
|
+
- doc-src/forms.md
|
440
|
+
- doc-src/handlers.md
|
441
|
+
- doc-src/javascript.md
|
442
|
+
- doc-src/keyword-injection.md
|
443
|
+
- doc-src/pages.md
|
444
|
+
- doc-src/route-hooks.md
|
340
445
|
- docker-compose.dx.yml
|
446
|
+
- docs-todo.md
|
341
447
|
- dx/build
|
342
448
|
- dx/docker-compose.env
|
343
449
|
- dx/dx.sh.lib
|
@@ -348,8 +454,6 @@ files:
|
|
348
454
|
- dx/start
|
349
455
|
- dx/stop
|
350
456
|
- lib/brut.rb
|
351
|
-
- lib/brut/back_end/action.rb
|
352
|
-
- lib/brut/back_end/result.rb
|
353
457
|
- lib/brut/back_end/seed_data.rb
|
354
458
|
- lib/brut/back_end/validator.rb
|
355
459
|
- lib/brut/back_end/validators/form_validator.rb
|
@@ -374,38 +478,57 @@ files:
|
|
374
478
|
- lib/brut/framework/errors.rb
|
375
479
|
- lib/brut/framework/errors/abstract_method.rb
|
376
480
|
- lib/brut/framework/errors/bug.rb
|
481
|
+
- lib/brut/framework/errors/missing_parameter.rb
|
482
|
+
- lib/brut/framework/errors/no_class_for_path.rb
|
377
483
|
- lib/brut/framework/errors/not_found.rb
|
484
|
+
- lib/brut/framework/errors/not_implemented.rb
|
378
485
|
- lib/brut/framework/fussy_type_enforcement.rb
|
379
486
|
- lib/brut/framework/mcp.rb
|
380
487
|
- lib/brut/framework/project_environment.rb
|
381
488
|
- lib/brut/front_end/asset_metadata.rb
|
382
489
|
- lib/brut/front_end/component.rb
|
490
|
+
- lib/brut/front_end/components/constraint_violations.rb
|
383
491
|
- lib/brut/front_end/components/form_tag.rb
|
384
492
|
- lib/brut/front_end/components/i18n_translations.rb
|
385
493
|
- lib/brut/front_end/components/input.rb
|
386
494
|
- lib/brut/front_end/components/inputs/csrf_token.rb
|
495
|
+
- lib/brut/front_end/components/inputs/radio_button.rb
|
387
496
|
- lib/brut/front_end/components/inputs/select.rb
|
388
497
|
- lib/brut/front_end/components/inputs/text_field.rb
|
389
498
|
- lib/brut/front_end/components/inputs/textarea.rb
|
390
499
|
- lib/brut/front_end/components/locale_detection.rb
|
391
500
|
- lib/brut/front_end/components/page_identifier.rb
|
392
|
-
- lib/brut/front_end/components/
|
501
|
+
- lib/brut/front_end/components/time.rb
|
502
|
+
- lib/brut/front_end/components/traceparent.rb
|
393
503
|
- lib/brut/front_end/download.rb
|
394
504
|
- lib/brut/front_end/flash.rb
|
395
505
|
- lib/brut/front_end/form.rb
|
396
506
|
- lib/brut/front_end/forms/constraint_violation.rb
|
397
507
|
- lib/brut/front_end/forms/input.rb
|
508
|
+
- lib/brut/front_end/forms/input_declarations.rb
|
398
509
|
- lib/brut/front_end/forms/input_definition.rb
|
510
|
+
- lib/brut/front_end/forms/radio_button_group_input.rb
|
511
|
+
- lib/brut/front_end/forms/radio_button_group_input_definition.rb
|
512
|
+
- lib/brut/front_end/forms/select_input.rb
|
513
|
+
- lib/brut/front_end/forms/select_input_definition.rb
|
399
514
|
- lib/brut/front_end/forms/validity_state.rb
|
400
515
|
- lib/brut/front_end/handler.rb
|
401
516
|
- lib/brut/front_end/handlers/csp_reporting_handler.rb
|
517
|
+
- lib/brut/front_end/handlers/instrumentation_handler.rb
|
402
518
|
- lib/brut/front_end/handlers/locale_detection_handler.rb
|
519
|
+
- lib/brut/front_end/handlers/missing_handler.rb
|
403
520
|
- lib/brut/front_end/handling_results.rb
|
404
521
|
- lib/brut/front_end/http_method.rb
|
405
522
|
- lib/brut/front_end/http_status.rb
|
523
|
+
- lib/brut/front_end/layouts/_internal.html.erb
|
406
524
|
- lib/brut/front_end/middleware.rb
|
525
|
+
- lib/brut/front_end/middlewares/annotate_brut_owned_paths.rb
|
526
|
+
- lib/brut/front_end/middlewares/favicon.rb
|
527
|
+
- lib/brut/front_end/middlewares/open_telemetry_span.rb
|
407
528
|
- lib/brut/front_end/middlewares/reload_app.rb
|
408
529
|
- lib/brut/front_end/page.rb
|
530
|
+
- lib/brut/front_end/pages/_missing_page.html.erb
|
531
|
+
- lib/brut/front_end/pages/missing_page.rb
|
409
532
|
- lib/brut/front_end/request_context.rb
|
410
533
|
- lib/brut/front_end/route_hook.rb
|
411
534
|
- lib/brut/front_end/route_hooks/age_flash.rb
|
@@ -421,20 +544,22 @@ files:
|
|
421
544
|
- lib/brut/front_end/templates/erb_parser.rb
|
422
545
|
- lib/brut/front_end/templates/escapable_filter.rb
|
423
546
|
- lib/brut/front_end/templates/html_safe_string.rb
|
547
|
+
- lib/brut/front_end/templates/locator.rb
|
424
548
|
- lib/brut/i18n.rb
|
425
549
|
- lib/brut/i18n/base_methods.rb
|
426
550
|
- lib/brut/i18n/for_cli.rb
|
427
551
|
- lib/brut/i18n/for_html.rb
|
428
552
|
- lib/brut/i18n/http_accept_language.rb
|
429
553
|
- lib/brut/instrumentation.rb
|
430
|
-
- lib/brut/instrumentation/
|
431
|
-
- lib/brut/instrumentation/
|
432
|
-
- lib/brut/instrumentation/http_event.rb
|
433
|
-
- lib/brut/instrumentation/subscriber.rb
|
554
|
+
- lib/brut/instrumentation/logger_span_exporter.rb
|
555
|
+
- lib/brut/instrumentation/open_telemetry.rb
|
434
556
|
- lib/brut/junk_drawer.rb
|
435
557
|
- lib/brut/sinatra_helpers.rb
|
436
558
|
- lib/brut/spec_support.rb
|
559
|
+
- lib/brut/spec_support/clock_support.rb
|
437
560
|
- lib/brut/spec_support/component_support.rb
|
561
|
+
- lib/brut/spec_support/e2e_test_server.rb
|
562
|
+
- lib/brut/spec_support/enhanced_node.rb
|
438
563
|
- lib/brut/spec_support/flash_support.rb
|
439
564
|
- lib/brut/spec_support/general_support.rb
|
440
565
|
- lib/brut/spec_support/handler_support.rb
|
@@ -444,8 +569,12 @@ files:
|
|
444
569
|
- lib/brut/spec_support/matchers/be_routing_for.rb
|
445
570
|
- lib/brut/spec_support/matchers/have_constraint_violation.rb
|
446
571
|
- lib/brut/spec_support/matchers/have_html_attribute.rb
|
572
|
+
- lib/brut/spec_support/matchers/have_i18n_string.rb
|
573
|
+
- lib/brut/spec_support/matchers/have_link_to.rb
|
574
|
+
- lib/brut/spec_support/matchers/have_redirected_to.rb
|
447
575
|
- lib/brut/spec_support/matchers/have_rendered.rb
|
448
576
|
- lib/brut/spec_support/matchers/have_returned_http_status.rb
|
577
|
+
- lib/brut/spec_support/rspec_setup.rb
|
449
578
|
- lib/brut/spec_support/session_support.rb
|
450
579
|
- lib/brut/version.rb
|
451
580
|
- lib/sequel/extensions/brut_instrumentation.rb
|
@@ -461,7 +590,6 @@ metadata:
|
|
461
590
|
homepage_uri: https://naildrivin5.com
|
462
591
|
source_code_uri: https://naildrivin5.com
|
463
592
|
changelog_uri: https://naildrivin5.com
|
464
|
-
post_install_message:
|
465
593
|
rdoc_options: []
|
466
594
|
require_paths:
|
467
595
|
- lib
|
@@ -476,8 +604,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
476
604
|
- !ruby/object:Gem::Version
|
477
605
|
version: '0'
|
478
606
|
requirements: []
|
479
|
-
rubygems_version: 3.
|
480
|
-
signing_key:
|
607
|
+
rubygems_version: 3.6.4
|
481
608
|
specification_version: 4
|
482
609
|
summary: NOT YET RELEASED - Web Framework Built around Ruby, Web Standards, Simplicity,
|
483
610
|
and Object-Orientation
|
data/lib/brut/back_end/action.rb
DELETED
data/lib/brut/back_end/result.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
# The result of back-end processing, which is essentially
|
2
|
-
# a container for constraint violations and arbitrary context.
|
3
|
-
class Brut::BackEnd::Result
|
4
|
-
attr_reader :constraint_violations, :context
|
5
|
-
|
6
|
-
def initialize
|
7
|
-
@constraint_violations = {}
|
8
|
-
@context = {}
|
9
|
-
end
|
10
|
-
|
11
|
-
def constraint_violation!(object:,
|
12
|
-
field:,
|
13
|
-
key:,
|
14
|
-
context: {})
|
15
|
-
@constraint_violations[object] ||= {}
|
16
|
-
@constraint_violations[object][field] ||= {}
|
17
|
-
@constraint_violations[object][field][key] = context
|
18
|
-
end
|
19
|
-
|
20
|
-
def each_violation(&block)
|
21
|
-
@constraint_violations.each do |object,fields|
|
22
|
-
fields.each do |field,keys|
|
23
|
-
keys.each do |key,context|
|
24
|
-
block.(object,field,key,context)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def []=(key_in_context,object)
|
31
|
-
@context[key_in_context] = object
|
32
|
-
end
|
33
|
-
|
34
|
-
def [](key_in_context)
|
35
|
-
@context.fetch(key_in_context)
|
36
|
-
rescue KeyError => ex
|
37
|
-
raise KeyError.new(
|
38
|
-
"Context did not contain '#{key_in_context}' (#{key_in_context.class}). Context has these keys: #{@context.keys.join(',')}",
|
39
|
-
receiver: ex.receiver,
|
40
|
-
key: ex.key)
|
41
|
-
end
|
42
|
-
|
43
|
-
|
44
|
-
def constraint_violations? = self.constraint_violations.any?
|
45
|
-
|
46
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
require "rexml"
|
2
|
-
class Brut::FrontEnd::Components::Timestamp < Brut::FrontEnd::Component
|
3
|
-
include Brut::I18n::ForHTML
|
4
|
-
def initialize(timestamp:, format: :full, skip_year_if_same: true, attribute_format: :iso_8601, **only_contains_class)
|
5
|
-
@timestamp = timestamp
|
6
|
-
formats = [ format ]
|
7
|
-
if @timestamp.year == Time.now.year && skip_year_if_same
|
8
|
-
formats.unshift("#{format}_no_year")
|
9
|
-
end
|
10
|
-
format_keys = formats.map { |f| "time.formats.#{f}" }
|
11
|
-
found_format = formats.zip(::I18n.t(format_keys)).detect { |(key,value)|
|
12
|
-
value !~ /^Translation missing/
|
13
|
-
}.first
|
14
|
-
if found_format.nil?
|
15
|
-
raise ArgumentError,"format #{format} is not a known time format"
|
16
|
-
end
|
17
|
-
@format = found_format.to_sym
|
18
|
-
|
19
|
-
if ::I18n.t("time.formats.#{attribute_format}") =~ /^Translation missing/
|
20
|
-
raise ArgumentError,"attribute_format #{attribute_format} is not a known time format"
|
21
|
-
end
|
22
|
-
@attribute_format = attribute_format.to_sym
|
23
|
-
@class_attribute = only_contains_class[:class] || ""
|
24
|
-
end
|
25
|
-
|
26
|
-
|
27
|
-
def render(clock:)
|
28
|
-
timestamp_in_time_zone = clock.in_time_zone(@timestamp)
|
29
|
-
html_tag(:time, class: @class_attribute, datetime: ::I18n.l(timestamp_in_time_zone,format: @attribute_format)) do
|
30
|
-
::I18n.l(timestamp_in_time_zone,format: @format)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
@@ -1,66 +0,0 @@
|
|
1
|
-
class Brut::Instrumentation::Basic
|
2
|
-
def initialize
|
3
|
-
@subscribers = Concurrent::Set.new
|
4
|
-
end
|
5
|
-
|
6
|
-
class TypeChecking < Brut::Instrumentation::Basic
|
7
|
-
def instrument(event,&block)
|
8
|
-
if !event.kind_of?(Brut::Instrumentation::Event)
|
9
|
-
raise "You cannot instrument a #{event.class} - it must be a Brut::Instrumentation::Event or subclass"
|
10
|
-
end
|
11
|
-
super
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def instrument(event,&block)
|
16
|
-
block ||= ->() {}
|
17
|
-
|
18
|
-
start = Time.now
|
19
|
-
result = nil
|
20
|
-
exception = nil
|
21
|
-
|
22
|
-
begin
|
23
|
-
result = block.(event)
|
24
|
-
rescue => ex
|
25
|
-
exception = ex
|
26
|
-
end
|
27
|
-
stop = Time.now
|
28
|
-
notify(event:,start:,stop:,exception:)
|
29
|
-
if exception
|
30
|
-
raise exception
|
31
|
-
else
|
32
|
-
result
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def subscribe(subscriber=:use_block,&block)
|
37
|
-
if block.nil? && subscriber == :use_block
|
38
|
-
raise ArgumentError,"subscriber requires a Brut::Instrumentation::Subscriber or a block"
|
39
|
-
end
|
40
|
-
if !block.nil? && subscriber != :use_block
|
41
|
-
raise ArgumentError,"subscriber requires a Brut::Instrumentation::Subscriber or a block, not both"
|
42
|
-
end
|
43
|
-
if block.nil?
|
44
|
-
if subscriber.kind_of?(Proc)
|
45
|
-
subscriber = Brut::Instrumentation::Subscriber.from_proc(subscriber)
|
46
|
-
elsif !subscriber.kind_of?(Brut::Instrumentation::Subscriber)
|
47
|
-
raise ArgumentError, "subscriber must be a Proc or Brut::Instrumentation::Subscriber, not a #{subscriber.class}"
|
48
|
-
end
|
49
|
-
else
|
50
|
-
subscriber = Brut::Instrumentation::Subscriber.from_proc(block)
|
51
|
-
end
|
52
|
-
@subscribers << subscriber
|
53
|
-
end
|
54
|
-
|
55
|
-
def notify(event:,start:,stop:,exception:)
|
56
|
-
Thread.new do
|
57
|
-
@subscribers.each do |subscriber|
|
58
|
-
begin
|
59
|
-
subscriber.(event:,start:,stop:,exception:)
|
60
|
-
rescue => ex
|
61
|
-
warn "#{subscriber} raised #{ex}"
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
class Brut::Instrumentation::Event
|
2
|
-
include Brut::Framework::FussyTypeEnforcement
|
3
|
-
|
4
|
-
attr_reader :category,
|
5
|
-
:subcategory,
|
6
|
-
:name,
|
7
|
-
:details
|
8
|
-
|
9
|
-
def initialize(category:,
|
10
|
-
subcategory:nil,
|
11
|
-
name:,
|
12
|
-
details:{})
|
13
|
-
@category = type!(category,String,"category",required: true, coerce: :to_s)
|
14
|
-
@subcategory = type!(subcategory,String,"subcategory",required: false, coerce: :to_s)
|
15
|
-
@name = type!(name,String,"name",required:true,coerce: :to_s)
|
16
|
-
@details = type!(details,Hash,"details",required:false) || {}
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
class Brut::Instrumentation::Subscriber
|
2
|
-
def self.from_proc(block)
|
3
|
-
required_parameter_names_found = self.instance_method(:call).parameters.map { |(type,name)| [ name, false ] }.to_h
|
4
|
-
unexpected_parameter_names_error = {}
|
5
|
-
|
6
|
-
block.parameters.each do |(type,name)|
|
7
|
-
if required_parameter_names_found.key?(name)
|
8
|
-
if type == :key || type == :keyreq
|
9
|
-
required_parameter_names_found[name] = true
|
10
|
-
else
|
11
|
-
unexpected_parameter_names[name] = "Not a keyword arg"
|
12
|
-
end
|
13
|
-
elsif type != :key
|
14
|
-
if type == :keyreq
|
15
|
-
unexpected_parameter_names[name] = "keyword arg without a default value"
|
16
|
-
else
|
17
|
-
unexpected_parameter_names[name] = "Not a keyword arg"
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
errors = []
|
22
|
-
if unexpected_parameter_names_error.any?
|
23
|
-
messages = unexpected_parameter_names_error.map { |name,problem|
|
24
|
-
"#{name} - #{problem}"
|
25
|
-
}.join(", ")
|
26
|
-
errors << "Unexpected parameters were required, so this cannot be used as a subscriber: #{messages}"
|
27
|
-
end
|
28
|
-
if required_parameter_names_found.any? { |_name,found| !found }
|
29
|
-
messages = required_parameter_names_found.select { |_name,found| !found }.map { |name,_found| "#{name} must be a keyword argument" }.join(",")
|
30
|
-
errors << "Required parameters were missing, so this cannot be used as a subscriber: #{messages}"
|
31
|
-
end
|
32
|
-
if errors.any?
|
33
|
-
raise ArgumentError,errors.join(", ")
|
34
|
-
end
|
35
|
-
block
|
36
|
-
end
|
37
|
-
|
38
|
-
def call(event:,start:,stop:,exception:)
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|