briefly 0.1.0 → 0.2.0

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.
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Briefly
4
+ # An ordered list of facade-wide and global +rescue_from+ registrations, queried at dispatch time.
5
+ # A shortcut's own handlers live on the {Briefly::Shortcut}, not here — this holds only the
6
+ # unscoped handlers a single shortcut cannot voice.
7
+ #
8
+ # Entries are stored oldest-first and matched newest-first, so the most recent registration for a
9
+ # given error class wins. Reads are lock-free against a frozen array; writes rebind it under a
10
+ # mutex, because rebinding alone would drop concurrent registrations.
11
+ class Rescues
12
+ # A single registration.
13
+ Entry = Struct.new(:klass, :handler)
14
+
15
+ def initialize
16
+ @entries = [].freeze
17
+ @mutex = Mutex.new
18
+ end
19
+
20
+ # @api private
21
+ # @param klass [Class] matched against the raised error and its subclasses
22
+ # @param handler [Proc] called with +(error, shortcut_name)+
23
+ # @return [self]
24
+ def add(klass, handler)
25
+ @mutex.synchronize { @entries = [*@entries, Entry.new(klass, handler)].freeze }
26
+ self
27
+ end
28
+
29
+ # @api private
30
+ # @param error [Exception]
31
+ # @return [Proc, nil] the most recently registered handler whose class matches +error+, or +nil+
32
+ def handler_for(error) = @entries.reverse_each.find { |entry| error.is_a?(entry.klass) }&.handler
33
+
34
+ # @api private
35
+ # @return [Integer] how many registrations the registry holds
36
+ def size = @entries.size
37
+
38
+ # Drops every registration. Reach it as +Briefly.rescues.clear+ to reset globally registered
39
+ # handlers between test examples, so a handler from one example cannot leak into the next.
40
+ #
41
+ # @return [self]
42
+ def clear
43
+ @mutex.synchronize { @entries = [].freeze }
44
+ self
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Briefly
4
+ # One shortcut — and the object {Briefly::Builder#shortcut} hands back so you can refine it. A
5
+ # declaration's memoization and its scoped error handlers both live here, on the shortcut itself, so
6
+ # refining after a redeclaration affects the declaration you named, exactly as its body and aliases do.
7
+ #
8
+ # shortcut(:catalog) { Catalog.load }.memoize
9
+ # shortcut(:redis) { REDIS_POOL }.rescue_from(Redis::BaseError) { nil }
10
+ #
11
+ # The name, aliases, body and location are internal; {#memoize} and {#rescue_from} are its public
12
+ # refinement surface. It holds no {Briefly::Builder} reference — both refinements are self-contained.
13
+ class Shortcut
14
+ # @api private
15
+ # @return [Symbol] the primary method name
16
+ attr_reader :canonical
17
+
18
+ # @api private
19
+ # @return [Array<Symbol>] additional method names delegating to the same body and memo cell
20
+ attr_reader :aliases
21
+
22
+ # @api private
23
+ # @return [Proc] the implementation, bound to the facade at call time
24
+ attr_reader :body
25
+
26
+ # @api private
27
+ # @return [Symbol] the private singleton method the body compiles to
28
+ attr_reader :raw_name
29
+
30
+ # @api private
31
+ # @return [Array<Array(Class, Proc)>] this shortcut's own error handlers, oldest first
32
+ attr_reader :rescues
33
+
34
+ # The +[file, line]+ the compiled methods report. {Briefly::Builder#shortcut} resolves it — the body's
35
+ # own location, or the +shortcut+ call site for a location-less Proc like +&:upcase+ — and
36
+ # {Briefly::Builder#namespace} overwrites it: its child-returning proc literal lives in +builder.rb+,
37
+ # and a namespace that pointed there would reintroduce, for namespaces, the lie this field exists to
38
+ # remove.
39
+ #
40
+ # @api private
41
+ # @return [Array(String, Integer)]
42
+ attr_accessor :source_location
43
+
44
+ # @param canonical [Symbol]
45
+ # @param aliases [Array<Symbol>]
46
+ # @param body [Proc]
47
+ # @param source_location [Array(String, Integer)]
48
+ def initialize(canonical, aliases, body, source_location)
49
+ @canonical = canonical
50
+ @aliases = aliases
51
+ @body = body
52
+ @raw_name = Candor.body_name(canonical)
53
+ @memoized = false
54
+ @rescues = []
55
+ @source_location = source_location
56
+ end
57
+
58
+ # Builder copies the facade's shortcuts before mutating them, so an aborted pass cannot leave the
59
+ # live facade half-configured. Hash#dup would share these arrays.
60
+ #
61
+ # @param other [Briefly::Shortcut]
62
+ # @return [void]
63
+ def initialize_copy(other)
64
+ super
65
+ @aliases = other.aliases.dup
66
+ @rescues = other.rescues.dup
67
+ end
68
+
69
+ # Memoizes the value: computed once, cached for the process lifetime. A body that takes any
70
+ # argument is refused at build time (in {Briefly::Builder#compile!}); the compiled method takes none.
71
+ #
72
+ # @return [self]
73
+ def memoize
74
+ @memoized = true
75
+ self
76
+ end
77
+
78
+ # @api private
79
+ # @return [Boolean]
80
+ def memoized? = @memoized
81
+
82
+ # Registers an error handler scoped to this shortcut. The handler's return value becomes the
83
+ # shortcut's value; it is +call+ed with +(error, shortcut_name)+, never bound to the facade. Later
84
+ # registrations for the same error class win.
85
+ #
86
+ # @param error_class [Class] matched against the raised error and its subclasses
87
+ # @yield [error, shortcut_name] the recovery block
88
+ # @return [self]
89
+ def rescue_from(error_class, &handler)
90
+ Briefly.send(:validate_rescue!, error_class, handler)
91
+ @rescues << [error_class, handler]
92
+ self
93
+ end
94
+
95
+ # @api private
96
+ # @param error [Exception]
97
+ # @return [Proc, nil] this shortcut's most recently registered handler whose class matches, or +nil+
98
+ def handler_for(error) = @rescues.reverse_each.find { |klass, _| error.is_a?(klass) }&.last
99
+
100
+ # @api private
101
+ # @return [Array<Symbol>] canonical name followed by every alias
102
+ def names = [@canonical, *@aliases]
103
+ end
104
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Briefly
4
4
  # The gem version.
5
- VERSION = "0.1.0"
5
+ VERSION = "0.2.0"
6
6
  end
data/lib/briefly.rb CHANGED
@@ -4,8 +4,8 @@ require "candor"
4
4
 
5
5
  require "briefly/version"
6
6
  require "briefly/errors"
7
- require "briefly/definition"
8
- require "briefly/error_registry"
7
+ require "briefly/shortcut"
8
+ require "briefly/rescues"
9
9
  require "briefly/facade"
10
10
  require "briefly/builder"
11
11
 
@@ -18,7 +18,7 @@ require "briefly/builder"
18
18
  module Briefly
19
19
  autoload :Rails, "briefly/rails"
20
20
 
21
- @errors = ErrorRegistry.new
21
+ @rescues = Rescues.new
22
22
 
23
23
  # The packs this gem ships, under the short names +use+ accepts. Values are constant paths, never
24
24
  # constants: naming +Briefly::Rails::DB+ here would resolve it at load and defeat the autoload above.
@@ -28,6 +28,7 @@ module Briefly
28
28
  "rails/env" => "Briefly::Rails::Env",
29
29
  "rails/view" => "Briefly::Rails::View",
30
30
  "rails/db" => "Briefly::Rails::DB",
31
+ "rails/instrument" => "Briefly::Rails::Instrument",
31
32
  "rails/reload" => "Briefly::Rails::Reload"
32
33
  }
33
34
 
@@ -36,7 +37,7 @@ module Briefly
36
37
  #
37
38
  # @yield [] the shortcut declarations
38
39
  # @return [Briefly::Facade]
39
- def define(&) = Facade.new.configure(&)
40
+ def define(&) = Facade.new.briefly.configure(&)
40
41
 
41
42
  # Registers a pack under a short name, so +use "myapp/redis"+ resolves it. Re-registering a name
42
43
  # overrides it. There is no inflection and no path guessing: this table is the only source of truth.
@@ -79,16 +80,32 @@ module Briefly
79
80
  # @yield [error, shortcut_name] the recovery block; its return value becomes the shortcut's value
80
81
  # @return [self]
81
82
  def rescue_from(error_class, &handler)
83
+ validate_rescue!(error_class, handler)
84
+ @rescues.add(error_class, handler)
85
+ self
86
+ end
87
+
88
+ # The one +rescue_from+ argument check, shared by the global verb here, the facade-wide verb
89
+ # ({Briefly::Builder#rescue_from}) and the per-shortcut form ({Briefly::Shortcut#rescue_from}), so
90
+ # the error class must come first, a block is required, and the message never diverges between them.
91
+ # Private, so it stays off +Briefly+'s public surface; the two cross-class callers reach it with
92
+ # +Briefly.send(:validate_rescue!, ...)+, the same +send+-to-internal seam {Briefly::Facade::Control} uses.
93
+ #
94
+ # @api private
95
+ # @param error_class [Object] must be a Class
96
+ # @param handler [Proc, nil] must be present
97
+ # @return [void]
98
+ # @raise [ArgumentError] if +error_class+ is not a Class, or no block was given
99
+ def validate_rescue!(error_class, handler)
82
100
  unless error_class.is_a?(Class)
83
101
  raise ArgumentError, "rescue_from expects the error class first, got #{error_class.inspect}"
84
102
  end
85
- raise ArgumentError, "rescue_from(#{error_class}) requires a block" unless handler
86
103
 
87
- @errors.add(error_class, nil, handler)
88
- self
104
+ raise ArgumentError, "rescue_from(#{error_class}) requires a block" unless handler
89
105
  end
106
+ private :validate_rescue!
90
107
 
91
- # @return [Briefly::ErrorRegistry] the global registry
92
- attr_reader :errors
108
+ # @return [Briefly::Rescues] the global registry
109
+ attr_reader :rescues
93
110
  end
94
111
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators/base"
4
+
5
+ module Briefly
6
+ # Namespace for briefly's Rails generators, discovered by `rails generate`.
7
+ module Generators
8
+ # Writes +config/initializers/briefly.rb+: a working +Briefly.define { use "rails" }+ facade plus a
9
+ # commented, concern-grouped map of every shortcut the +rails+ pack installs. Re-run it to update —
10
+ # Rails prompts before overwriting, so the map refreshes after a gem upgrade.
11
+ #
12
+ # rails generate briefly:install # => App = Briefly.define { use "rails" }
13
+ # rails generate briefly:install Facade # => Facade = Briefly.define { use "rails" }
14
+ #
15
+ # +::Rails+ is fully qualified throughout: a bare +Rails+ here would resolve to {Briefly::Rails},
16
+ # the pack, not the framework. There is deliberately no +sig/+ entry: generators load only under
17
+ # railties, outside the gem's typed runtime surface.
18
+ class InstallGenerator < ::Rails::Generators::Base
19
+ source_root File.expand_path("templates", __dir__)
20
+
21
+ argument :name, type: :string, default: "App", banner: "ConstantName"
22
+
23
+ # @return [void]
24
+ def create_initializer
25
+ template "briefly.rb.tt", "config/initializers/briefly.rb"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ # briefly — a terse, curated facade over your app's most reached-for objects.
4
+ # Re-run `rails g briefly:install` after upgrading to refresh the map below. It rewrites this whole
5
+ # file (Rails shows a diff first), so keep any shortcuts you add here under version control.
6
+ <%= name %> = Briefly.define do
7
+ use "rails"
8
+
9
+ # Your own shortcuts go here (a body can call the other shortcuts). `shortcut` returns the shortcut
10
+ # you refine: chain `.memoize` to compute once, or `.rescue_from(Error) { fallback }` to recover — in
11
+ # any order. `rescue_from` on its own line stays for facade-wide handlers.
12
+ # shortcut(:redis) { REDIS_POOL }
13
+ # shortcut(:stripe) { Stripe::Client.new(x.stripe_key) }
14
+ # shortcut(:payments) { config_for(:payments) }.memoize # compute once (cleared on reload)
15
+ # shortcut(:cache) { Redis.new }.rescue_from(Redis::CannotConnectError) { NullCache.new }
16
+ end
17
+
18
+ # --- What `use "rails"` gives you (call as `<%= name %>.<shortcut>`), by concern ---
19
+ #
20
+ # config <%= name %>.config, <%= name %>.c -> Rails.configuration
21
+ # <%= name %>.config_x, <%= name %>.x -> Rails.configuration.x
22
+ # <%= name %>.root -> Rails.root
23
+ # <%= name %>.cache -> Rails.cache
24
+ # <%= name %>.logger, <%= name %>.log -> Rails.logger
25
+ # <%= name %>.credentials, <%= name %>.cred -> Rails.application.credentials
26
+ # <%= name %>.error -> Rails.error (.report(e) / .handle { })
27
+ # <%= name %>.config_for(:key, env:) -> Rails.application.config_for (env: optional)
28
+ #
29
+ # env <%= name %>.env -> Rails.env
30
+ # <%= name %>.production?, <%= name %>.prod? <%= name %>.development?, <%= name %>.dev? <%= name %>.test? <%= name %>.local?
31
+ #
32
+ # view <%= name %>.helpers, <%= name %>.h -> ApplicationController.helpers
33
+ # <%= name %>.routes, <%= name %>.r -> Rails.application.routes.url_helpers
34
+ # <%= name %>.renderer -> ApplicationController.renderer
35
+ # <%= name %>.render(:tmpl, locals:) -> renderer.render
36
+ #
37
+ # notify <%= name %>.instrument(event, payload) { } -> ActiveSupport::Notifications
38
+ #
39
+ # db <%= name %>.db.connection { |c| }, <%= name %>.db.conn { |c| } -> yields a connection, auto-releases
40
+ # <%= name %>.db.transaction { }, <%= name %>.db.txn { } -> wraps the block in a transaction
41
+ # <%= name %>.db.select(sql, id: 1) / select(sql, 1) -> a read (SELECT); named or positional binds
42
+ # <%= name %>.db.query(sql, id: 1) / query(sql, 1) -> arbitrary SQL (writes, DDL); same binds
43
+ # <%= name %>.db.connected_to(role:, shard:, prevent_writes:) { }
44
+ # <%= name %>.db.reading { }, <%= name %>.db.writing { } -> run the block under a role
45
+ #
46
+ # Facades are cheap and share no state — add another for a separate concern:
47
+ # Db = Briefly.define { use "rails/db" }
@@ -1,28 +1,38 @@
1
1
  module Briefly
2
2
  # Receives the DSL. Blocks are `instance_eval`'d here, never on the facade.
3
3
  class Builder
4
+ # A validated `compile!` pass, ready for a `Facade` to install.
5
+ class Plan < ::Struct[untyped]
6
+ attr_accessor defs: Hash[Symbol, Shortcut]
7
+ attr_accessor rescue_entries: Array[Briefly::rescue_entry]
8
+ attr_accessor children: Hash[Symbol, Facade]
9
+ attr_accessor child_plans: Array[[ Facade, Plan ]]
10
+
11
+ def self.new: (Hash[Symbol, Shortcut] defs, Array[Briefly::rescue_entry] rescue_entries, Hash[Symbol, Facade] children, Array[[ Facade, Plan ]] child_plans) -> Plan
12
+ end
13
+
4
14
  @facade: Facade
5
- @defs: Hash[Symbol, Definition]
15
+ @defs: Hash[Symbol, Shortcut]
6
16
  @children: Hash[Symbol, Facade]
7
- @errors: Array[Briefly::error_entry]
17
+ @rescues: Array[Briefly::rescue_entry]
8
18
 
9
19
  # One collected namespace pass per name, held until `compile!` has validated the whole tree.
10
20
  @pending: Hash[Symbol, Builder]
11
21
 
12
22
  attr_reader facade: Facade
13
23
 
14
- def initialize: (Facade facade, Hash[Symbol, Definition] defs, Hash[Symbol, Facade] children) -> void
24
+ def initialize: (Facade facade, Hash[Symbol, Shortcut] defs, Hash[Symbol, Facade] children) -> void
15
25
  def use: (pack_ref pack, **untyped opts) -> self
16
26
  def namespace: (Symbol name) { (?) [self: Builder] -> void } -> Symbol
17
- def shortcut: (Symbol canonical, *Symbol aliases) { (?) [self: Facade] -> untyped } -> Symbol
18
- def memoize: (Symbol name, **untyped opts) -> Symbol
19
- def rescue_from: (Class error_class, *(Symbol | Array[Symbol]) names) { (StandardError, Symbol) -> untyped } -> self
20
- def compile!: () -> Briefly::plan
27
+ def shortcut: (Symbol canonical, *Symbol aliases) ?{ (?) [self: Facade] -> untyped } -> Shortcut
28
+ def rescue_from: (Class error_class, *Symbol names) { (StandardError, Symbol) -> untyped } -> self
29
+ def compile!: () -> Plan
21
30
 
22
31
  private
23
32
 
33
+ def source_location_for: (Proc body) -> [ String, Integer ]
24
34
  def validate_name!: (untyped name) -> void
25
35
  def purge: (Array[Symbol] names, except: Symbol) -> void
26
- def fetch: (Symbol name) -> Definition
36
+ def fetch: (Symbol name) -> Shortcut
27
37
  end
28
38
  end
@@ -5,32 +5,46 @@ module Briefly
5
5
  # Names a shortcut may not take.
6
6
  RESERVED: Array[Symbol]
7
7
 
8
- @__defs: Hash[Symbol, Definition]
8
+ @__defs: Hash[Symbol, Shortcut]
9
9
  @__aliases: Hash[Symbol, Symbol]
10
10
  @__memos: Hash[Symbol, untyped]
11
11
  @__monitor: Monitor
12
- @__errors: ErrorRegistry
13
- @__public: Array[Symbol]
12
+ @__rescues: Rescues
13
+ @__installed: Array[Symbol]
14
14
  @__children: Hash[Symbol, Facade]
15
15
 
16
16
  def initialize: () -> void
17
- def shortcuts: () -> Array[Symbol]
18
- def shortcut?: (Symbol name) -> bool
19
- def clear_memos!: () -> self
20
- def reset!: () -> self
21
- def configure: () ?{ (?) [self: Builder] -> void } -> self
17
+ def briefly: () -> Control
22
18
  def inspect: () -> String
23
19
  def to_s: () -> String
24
20
 
21
+ # The management surface, forwarded to the facade's private `__`-prefixed methods. Mutators return
22
+ # the facade; readers return their values.
23
+ class Control
24
+ @facade: Facade
25
+
26
+ def initialize: (Facade facade) -> void
27
+ def shortcuts: () -> Array[Symbol]
28
+ def shortcut?: (Symbol name) -> bool
29
+ def clear_memos!: () -> Facade
30
+ def configure: () ?{ (?) [self: Builder] -> void } -> Facade
31
+ def inspect: () -> String
32
+ def to_s: () -> String
33
+ end
34
+
25
35
  private
26
36
 
37
+ def __shortcuts: () -> Array[Symbol]
38
+ def __shortcut?: (Symbol name) -> bool
39
+ def __clear_memos!: () -> self
40
+ def __configure: () ?{ (?) [self: Builder] -> void } -> self
27
41
  def __prepare: () -> Builder
28
- def __commit: (Briefly::plan plan) -> self
29
- def __install: (Hash[Symbol, Definition] defs, Array[Briefly::error_entry] error_entries) -> self
42
+ def __commit: (Builder::Plan plan) -> self
43
+ def __install: (Hash[Symbol, Shortcut] defs, Array[Briefly::rescue_entry] rescue_entries) -> self
30
44
  def __remove_methods: (Array[Symbol] names) -> void
31
- def __define: (Definition defn) -> void
45
+ def __define: (Shortcut defn) -> void
32
46
  def __call: (Symbol name, *untyped, **untyped) ?{ (?) -> untyped } -> untyped
33
47
  def __memo: (Symbol name) { () -> untyped } -> untyped
34
- def __handle: (StandardError error, Symbol name) -> untyped
48
+ def __handle: (StandardError error, Shortcut defn) -> untyped
35
49
  end
36
50
  end
@@ -1,8 +1,8 @@
1
1
  module Briefly
2
2
  # Shortcut pack for Rails applications. Loaded only when `Briefly::Rails` is referenced.
3
3
  #
4
- # An umbrella over `Config`, `Env`, `View` and `Reload`, plus `DB` under the `db` namespace. Each
5
- # nested pack exposes `install` and nothing else.
4
+ # An umbrella over `Config`, `Env`, `View`, `Instrument` and `Reload`, plus `DB` under the `db`
5
+ # namespace. Each nested pack exposes `install` and nothing else.
6
6
  module Rails
7
7
  def self?.install: (Builder builder) -> Builder
8
8
 
@@ -21,6 +21,11 @@ module Briefly
21
21
  def self?.install: (Builder builder) -> Builder
22
22
  end
23
23
 
24
+ # ActiveSupport::Notifications instrumentation.
25
+ module Instrument
26
+ def self?.install: (Builder builder) -> Builder
27
+ end
28
+
24
29
  # One database, reached through one Active Record class. `base` is a constant path resolved on
25
30
  # every call, so a reloaded class is never captured.
26
31
  module DB
@@ -0,0 +1,21 @@
1
+ module Briefly
2
+ # An ordered list of facade-wide and global `rescue_from` registrations, queried at dispatch time.
3
+ class Rescues
4
+ # A single registration.
5
+ class Entry < ::Struct[untyped]
6
+ attr_accessor klass: Class
7
+ attr_accessor handler: Briefly::handler
8
+
9
+ def self.new: (Class klass, Briefly::handler handler) -> Entry
10
+ end
11
+
12
+ @entries: Array[Entry]
13
+ @mutex: Thread::Mutex
14
+
15
+ def initialize: () -> void
16
+ def add: (Class klass, Briefly::handler handler) -> self
17
+ def handler_for: (Exception error) -> Briefly::handler?
18
+ def size: () -> Integer
19
+ def clear: () -> self
20
+ end
21
+ end
@@ -1,10 +1,12 @@
1
1
  module Briefly
2
- # One shortcut declaration: its canonical name, its aliases, its body, and whether it memoizes.
3
- class Definition
2
+ # One shortcut, and the object `Builder#shortcut` returns so you can refine it. Its memoization and
3
+ # its own error handlers live here; `#memoize` and `#rescue_from` are the public refinement surface.
4
+ class Shortcut
4
5
  attr_reader canonical: Symbol
5
6
  attr_reader aliases: Array[Symbol]
6
7
  attr_reader body: Proc
7
8
  attr_reader raw_name: Symbol
9
+ attr_reader rescues: Array[[ Class, Briefly::handler ]]
8
10
 
9
11
  # The `[file, line]` the compiled methods report; `Builder#namespace` overwrites it.
10
12
  attr_accessor source_location: [ String, Integer ]
@@ -12,9 +14,11 @@ module Briefly
12
14
  @memoized: bool
13
15
 
14
16
  def initialize: (Symbol canonical, Array[Symbol] aliases, Proc body, [ String, Integer ] source_location) -> void
15
- def initialize_copy: (Definition other) -> void
16
- def memoize!: () -> void
17
+ def initialize_copy: (Shortcut other) -> void
18
+ def memoize: () -> self
17
19
  def memoized?: () -> bool
20
+ def rescue_from: (Class error_class) { (StandardError, Symbol) -> untyped } -> self
21
+ def handler_for: (Exception error) -> Briefly::handler?
18
22
  def names: () -> Array[Symbol]
19
23
  end
20
24
  end
data/sig/briefly.rbs CHANGED
@@ -9,7 +9,7 @@ module Briefly
9
9
  class Error < StandardError
10
10
  end
11
11
 
12
- # Raised when `memoize` or `rescue_from` names a shortcut that does not exist.
12
+ # Raised when a bodiless `shortcut` names a shortcut that does not exist.
13
13
  class UnknownShortcutError < Error
14
14
  end
15
15
 
@@ -24,13 +24,8 @@ module Briefly
24
24
  # A recovery block. Its return value becomes the shortcut's return value.
25
25
  type handler = ^(StandardError error, Symbol shortcut_name) -> untyped
26
26
 
27
- # A registered error handler, before `ErrorRegistry` receives it.
28
- type error_entry = [ Class, Array[Symbol]?, handler ]
29
-
30
- # A validated `configure` pass, ready to install: definitions, error handlers, namespace children,
31
- # and one `[child, plan]` pair per namespace this pass collected. Recursive, so RBS types the tail
32
- # as `untyped`.
33
- type plan = [ Hash[Symbol, Definition], Array[error_entry], Hash[Symbol, Facade], Array[[ Facade, untyped ]] ]
27
+ # A facade-wide rescue handler, before `Rescues` receives it.
28
+ type rescue_entry = [ Class, handler ]
34
29
 
35
30
  # A pack is any object responding to `#install(builder)`. Options are optional: Ruby drops an empty
36
31
  # `**` splat, so a pack that takes none needs no `**opts` parameter.
@@ -44,7 +39,7 @@ module Briefly
44
39
  # A registry entry: a pack, or a constant path resolved on first use.
45
40
  type pack_entry = _Pack | String
46
41
 
47
- self.@errors: ErrorRegistry
42
+ self.@rescues: Rescues
48
43
  self.@packs: Hash[String, pack_entry]
49
44
 
50
45
  # Shortcuts are compiled at runtime, so RBS cannot see them. Declare the ones you rely on in
@@ -53,5 +48,7 @@ module Briefly
53
48
  def self.register: (String | Symbol name, pack_entry pack) -> Module
54
49
  def self.pack: (String | Symbol name) -> _Pack
55
50
  def self.rescue_from: (Class error_class) { (StandardError, Symbol) -> untyped } -> Module
56
- def self.errors: () -> ErrorRegistry
51
+ def self.rescues: () -> Rescues
52
+
53
+ private def self.validate_rescue!: (untyped error_class, Proc? handler) -> void
57
54
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: briefly
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leonid Svyatov
@@ -40,20 +40,26 @@ files:
40
40
  - briefly.gemspec
41
41
  - lib/briefly.rb
42
42
  - lib/briefly/builder.rb
43
- - lib/briefly/definition.rb
44
- - lib/briefly/error_registry.rb
45
43
  - lib/briefly/errors.rb
46
44
  - lib/briefly/facade.rb
47
45
  - lib/briefly/rails.rb
46
+ - lib/briefly/rails/config.rb
48
47
  - lib/briefly/rails/db.rb
48
+ - lib/briefly/rails/env.rb
49
+ - lib/briefly/rails/instrument.rb
49
50
  - lib/briefly/rails/reload.rb
51
+ - lib/briefly/rails/view.rb
52
+ - lib/briefly/rescues.rb
53
+ - lib/briefly/shortcut.rb
50
54
  - lib/briefly/version.rb
55
+ - lib/generators/briefly/install/install_generator.rb
56
+ - lib/generators/briefly/install/templates/briefly.rb.tt
51
57
  - sig/briefly.rbs
52
58
  - sig/briefly/builder.rbs
53
- - sig/briefly/definition.rbs
54
- - sig/briefly/error_registry.rbs
55
59
  - sig/briefly/facade.rbs
56
60
  - sig/briefly/rails.rbs
61
+ - sig/briefly/rescues.rbs
62
+ - sig/briefly/shortcut.rbs
57
63
  - sig/manifest.yaml
58
64
  homepage: https://github.com/svyatov/briefly
59
65
  licenses:
@@ -1,64 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Briefly
4
- # One shortcut declaration: its canonical name, its aliases, its body, and whether it memoizes.
5
- #
6
- # @api private
7
- class Definition
8
- # @return [Symbol] the primary method name
9
- attr_reader :canonical
10
-
11
- # @return [Array<Symbol>] additional method names delegating to the same body and memo cell
12
- attr_reader :aliases
13
-
14
- # @return [Proc] the implementation, bound to the facade at call time
15
- attr_reader :body
16
-
17
- # @return [Symbol] the private singleton method the body compiles to
18
- attr_reader :raw_name
19
-
20
- # The +[file, line]+ the compiled methods report. {Briefly::Builder#shortcut} resolves it — the body's
21
- # own location, or the +shortcut+ call site for a bodiless-of-location Proc like +&:upcase+ — and
22
- # {Briefly::Builder#namespace} overwrites it: its child-returning proc literal lives in +builder.rb+,
23
- # and a namespace that pointed there would reintroduce, for namespaces, the lie this field exists to
24
- # remove.
25
- #
26
- # @return [Array(String, Integer)]
27
- attr_accessor :source_location
28
-
29
- # @param canonical [Symbol]
30
- # @param aliases [Array<Symbol>]
31
- # @param body [Proc]
32
- # @param source_location [Array(String, Integer)]
33
- def initialize(canonical, aliases, body, source_location)
34
- @canonical = canonical
35
- @aliases = aliases
36
- @body = body
37
- @raw_name = Candor.body_name(canonical)
38
- @memoized = false
39
- @source_location = source_location
40
- end
41
-
42
- # Builder copies the facade's definitions before mutating them, so an aborted pass cannot
43
- # leave the live facade half-configured. Hash#dup would share this array.
44
- #
45
- # @param other [Briefly::Definition]
46
- # @return [void]
47
- def initialize_copy(other)
48
- super
49
- @aliases = other.aliases.dup
50
- end
51
-
52
- # Marks the value as computed once and cached. A redeclared shortcut is a fresh, unmemoized
53
- # Definition, so there is no un-memoize.
54
- #
55
- # @return [void]
56
- def memoize! = @memoized = true
57
-
58
- # @return [Boolean]
59
- def memoized? = @memoized
60
-
61
- # @return [Array<Symbol>] canonical name followed by every alias
62
- def names = [@canonical, *@aliases]
63
- end
64
- end