falcon 0.36.4 → 0.37.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/lib/falcon/adapters/input.rb +32 -11
  3. data/lib/falcon/adapters/output.rb +20 -1
  4. data/lib/falcon/adapters/rack.rb +60 -39
  5. data/lib/falcon/adapters/response.rb +23 -1
  6. data/lib/falcon/adapters/rewindable.rb +10 -3
  7. data/lib/falcon/command.rb +2 -0
  8. data/lib/falcon/command/host.rb +22 -3
  9. data/lib/falcon/command/paths.rb +4 -0
  10. data/lib/falcon/command/proxy.rb +14 -0
  11. data/lib/falcon/command/redirect.rb +12 -0
  12. data/lib/falcon/command/serve.rb +27 -16
  13. data/lib/falcon/command/supervisor.rb +15 -1
  14. data/lib/falcon/command/top.rb +16 -0
  15. data/lib/falcon/command/virtual.rb +15 -0
  16. data/lib/falcon/configuration.rb +69 -7
  17. data/lib/falcon/controller/host.rb +12 -0
  18. data/lib/falcon/controller/proxy.rb +13 -0
  19. data/lib/falcon/controller/redirect.rb +7 -0
  20. data/lib/falcon/controller/serve.rb +17 -2
  21. data/lib/falcon/controller/virtual.rb +17 -0
  22. data/lib/falcon/endpoint.rb +8 -0
  23. data/lib/falcon/{configuration/proxy.rb → environments.rb} +9 -5
  24. data/lib/falcon/environments/application.rb +72 -0
  25. data/lib/falcon/{configuration/application.rb → environments/lets_encrypt_tls.rb} +21 -20
  26. data/lib/falcon/{configuration/lets_encrypt_tls.rb → environments/proxy.rb} +13 -6
  27. data/lib/falcon/{configuration → environments}/rack.rb +14 -2
  28. data/lib/falcon/{configuration → environments}/self_signed_tls.rb +9 -1
  29. data/lib/falcon/{configuration → environments}/supervisor.rb +19 -5
  30. data/lib/falcon/{configuration → environments}/tls.rb +39 -5
  31. data/lib/falcon/extensions/openssl.rb +1 -0
  32. data/lib/falcon/middleware/proxy.rb +26 -5
  33. data/lib/falcon/middleware/redirect.rb +11 -0
  34. data/lib/falcon/{verbose.rb → middleware/verbose.rb} +34 -26
  35. data/lib/falcon/proxy_endpoint.rb +21 -0
  36. data/lib/falcon/server.rb +8 -2
  37. data/lib/falcon/service/application.rb +24 -2
  38. data/lib/falcon/service/generic.rb +18 -0
  39. data/lib/falcon/service/proxy.rb +6 -0
  40. data/lib/falcon/service/supervisor.rb +13 -1
  41. data/lib/falcon/services.rb +21 -0
  42. data/lib/falcon/tls.rb +4 -2
  43. data/lib/falcon/version.rb +1 -1
  44. data/lib/rack/handler/falcon.rb +8 -2
  45. metadata +64 -121
  46. data/.editorconfig +0 -5
  47. data/.github/FUNDING.yml +0 -3
  48. data/.github/workflows/development.yml +0 -60
  49. data/.gitignore +0 -14
  50. data/.rspec +0 -3
  51. data/Gemfile +0 -17
  52. data/README.md +0 -316
  53. data/examples/beer/config.ru +0 -57
  54. data/examples/beer/falcon.rb +0 -8
  55. data/examples/benchmark/config.ru +0 -39
  56. data/examples/benchmark/falcon.rb +0 -6
  57. data/examples/csv/config.ru +0 -31
  58. data/examples/google/falcon.rb +0 -14
  59. data/examples/hello/config.ru +0 -22
  60. data/examples/hello/falcon.rb +0 -24
  61. data/examples/hello/preload.rb +0 -7
  62. data/examples/internet/config.ru +0 -54
  63. data/examples/memory/allocations.rb +0 -39
  64. data/examples/memory/config.ru +0 -14
  65. data/examples/push/client.rb +0 -29
  66. data/examples/push/config.ru +0 -28
  67. data/examples/push/index.html +0 -14
  68. data/examples/push/script.js +0 -2
  69. data/examples/push/style.css +0 -4
  70. data/examples/redis/Gemfile +0 -9
  71. data/examples/redis/config.ru +0 -28
  72. data/examples/sequel/Gemfile +0 -4
  73. data/examples/sequel/config.ru +0 -8
  74. data/examples/sequel/data.sqlite3 +0 -0
  75. data/examples/server/standalone.rb +0 -27
  76. data/examples/sinatra/Gemfile +0 -7
  77. data/examples/sinatra/Gemfile.lock +0 -53
  78. data/examples/sinatra/config.ru +0 -16
  79. data/examples/trailers/config.ru +0 -34
  80. data/examples/trailers/falcon.rb +0 -8
  81. data/falcon.gemspec +0 -45
  82. data/gems/rack1.gemfile +0 -4
  83. data/gems/rack3.gemfile +0 -4
  84. data/lib/falcon/adapters/early_hints.rb +0 -49
  85. data/logo-square.afdesign +0 -0
  86. data/logo.afdesign +0 -0
  87. data/logo.svg +0 -107
  88. data/server.rb +0 -21
  89. data/tasks/benchmark.rake +0 -103
@@ -24,13 +24,17 @@ require_relative '../configuration'
24
24
 
25
25
  module Falcon
26
26
  module Command
27
+ # A helper for resolving wildcard configuration paths.
27
28
  module Paths
29
+ # Resolve a set of `@paths` that may contain wildcards, into a sorted, unique array.
30
+ # @returns [Array(String)]
28
31
  def resolved_paths(&block)
29
32
  @paths.collect do |path|
30
33
  Dir.glob(path)
31
34
  end.flatten.sort.uniq.each(&block)
32
35
  end
33
36
 
37
+ # Build a configuration based on the resolved paths.
34
38
  def configuration
35
39
  configuration = Configuration.new
36
40
 
@@ -27,31 +27,44 @@ require 'samovar'
27
27
 
28
28
  module Falcon
29
29
  module Command
30
+ # Implements the `falcon proxy` command.
31
+ #
32
+ # Manages a {Controller::Proxy} instance which is responsible for proxing incoming requests.
30
33
  class Proxy < Samovar::Command
31
34
  self.description = "Proxy to one or more backend hosts."
32
35
 
36
+ # The command line options.
37
+ # @attribute [Samovar::Options]
33
38
  options do
34
39
  option '--bind <address>', "Bind to the given hostname/address", default: "https://[::]:443"
35
40
 
36
41
  option '-t/--timeout <duration>', "Specify the maximum time to wait for non-blocking operations.", type: Float, default: nil
37
42
  end
38
43
 
44
+ # One or more paths to the configuration files.
45
+ # @name paths
46
+ # @attribute [Array(String)]
39
47
  many :paths
40
48
 
41
49
  include Paths
42
50
 
51
+ # Prepare a new controller for the command.
43
52
  def controller
44
53
  Controller::Proxy.new(self)
45
54
  end
46
55
 
56
+ # The container class to use.
47
57
  def container_class
48
58
  Async::Container.best_container_class
49
59
  end
50
60
 
61
+ # Options for the container.
62
+ # See {Controller::Serve#setup}.
51
63
  def container_options
52
64
  {}
53
65
  end
54
66
 
67
+ # Prepare the environment and run the controller.
55
68
  def call
56
69
  Async.logger.info(self) do |buffer|
57
70
  buffer.puts "Falcon Proxy v#{VERSION} taking flight!"
@@ -63,6 +76,7 @@ module Falcon
63
76
  self.controller.run
64
77
  end
65
78
 
79
+ # The endpoint to bind to.
66
80
  def endpoint(**options)
67
81
  Async::HTTP::Endpoint.parse(@options[:bind], timeout: @options[:timeout], **options)
68
82
  end
@@ -30,6 +30,8 @@ module Falcon
30
30
  class Redirect < Samovar::Command
31
31
  self.description = "Redirect from insecure HTTP to secure HTTP."
32
32
 
33
+ # The command line options.
34
+ # @attribute [Samovar::Options]
33
35
  options do
34
36
  option '--bind <address>', "Bind to the given hostname/address", default: "http://[::]:80"
35
37
  option '--redirect <address>', "Redirect using this address as a template.", default: "https://[::]:443"
@@ -37,22 +39,30 @@ module Falcon
37
39
  option '-t/--timeout <duration>', "Specify the maximum time to wait for non-blocking operations.", type: Float, default: nil
38
40
  end
39
41
 
42
+ # One or more paths to the configuration files.
43
+ # @name paths
44
+ # @attribute [Array(String)]
40
45
  many :paths
41
46
 
42
47
  include Paths
43
48
 
49
+ # Prepare a new controller for the command.
44
50
  def controller
45
51
  Controller::Redirect.new(self)
46
52
  end
47
53
 
54
+ # The container class to use.
48
55
  def container_class
49
56
  Async::Container.best_container_class
50
57
  end
51
58
 
59
+ # Options for the container.
60
+ # See {Controller::Serve#setup}.
52
61
  def container_options
53
62
  {}
54
63
  end
55
64
 
65
+ # Prepare the environment and run the controller.
56
66
  def call
57
67
  Async.logger.info(self) do |buffer|
58
68
  buffer.puts "Falcon Redirect v#{VERSION} taking flight!"
@@ -64,10 +74,12 @@ module Falcon
64
74
  self.controller.run
65
75
  end
66
76
 
77
+ # The endpoint to bind to.
67
78
  def endpoint(**options)
68
79
  Async::HTTP::Endpoint.parse(@options[:bind], timeout: @options[:timeout], **options)
69
80
  end
70
81
 
82
+ # The template endpoint to redirect to.
71
83
  def redirect_endpoint(**options)
72
84
  Async::HTTP::Endpoint.parse(@options[:redirect], **options)
73
85
  end
@@ -40,9 +40,14 @@ require 'bundler'
40
40
 
41
41
  module Falcon
42
42
  module Command
43
+ # Implements the `falcon serve` command. Designed for *development*.
44
+ #
45
+ # Manages a {Controller::Serve} instance which is responsible for running applications in a development environment.
43
46
  class Serve < Samovar::Command
44
47
  self.description = "Run an HTTP server for development purposes."
45
48
 
49
+ # The command line options.
50
+ # @attribute [Samovar::Options]
46
51
  options do
47
52
  option '-b/--bind <address>', "Bind to the given hostname/address.", default: "https://localhost:9292"
48
53
 
@@ -63,6 +68,7 @@ module Falcon
63
68
  option '--threads <count>', "Number of threads (hybrid only).", type: Integer
64
69
  end
65
70
 
71
+ # The container class to use.
66
72
  def container_class
67
73
  case @options[:container]
68
74
  when :threaded
@@ -74,57 +80,58 @@ module Falcon
74
80
  end
75
81
  end
76
82
 
83
+ # Whether verbose logging is enabled.
84
+ # @returns [Boolean]
77
85
  def verbose?
78
86
  @parent&.verbose?
79
87
  end
80
88
 
89
+ # Whether to enable the application HTTP cache.
90
+ # @returns [Boolean]
81
91
  def cache?
82
92
  @options[:cache]
83
93
  end
84
94
 
95
+ # Load the rack application from the specified configuration path.
96
+ # @returns [Protocol::HTTP::Middleware]
85
97
  def load_app
86
98
  rack_app, _ = Rack::Builder.parse_file(@options[:config])
87
99
 
88
100
  return Server.middleware(rack_app, verbose: self.verbose?, cache: self.cache?)
89
101
  end
90
102
 
91
- def slice_options(*keys)
92
- # TODO: Ruby 2.5 introduced Hash#slice
93
- options = {}
94
-
95
- keys.each do |key|
96
- if @options.key?(key)
97
- options[key] = @options[key]
98
- end
99
- end
100
-
101
- return options
102
- end
103
-
103
+ # Options for the container.
104
+ # See {Controller::Serve#setup}.
104
105
  def container_options
105
- slice_options(:count, :forks, :threads)
106
+ @options.slice(:count, :forks, :threads)
106
107
  end
107
108
 
109
+ # Options for the {endpoint}.
108
110
  def endpoint_options
109
- slice_options(:hostname, :port, :reuse_port, :timeout)
111
+ @options.slice(:hostname, :port, :reuse_port, :timeout)
110
112
  end
111
113
 
114
+ # The endpoint to bind to.
112
115
  def endpoint
113
116
  Endpoint.parse(@options[:bind], **endpoint_options)
114
117
  end
115
118
 
119
+ # The endpoint suitable for a client to connect.
116
120
  def client_endpoint
117
121
  Async::HTTP::Endpoint.parse(@options[:bind], **endpoint_options)
118
122
  end
119
123
 
124
+ # Create a new client suitable for accessing the application.
120
125
  def client
121
126
  Async::HTTP::Client.new(client_endpoint)
122
127
  end
123
128
 
129
+ # Prepare a new controller for the command.
124
130
  def controller
125
131
  Controller::Serve.new(self)
126
132
  end
127
133
 
134
+ # Prepare the environment and run the controller.
128
135
  def call
129
136
  Async.logger.info(self) do |buffer|
130
137
  buffer.puts "Falcon v#{VERSION} taking flight! Using #{self.container_class} #{self.container_options}."
@@ -138,7 +145,11 @@ module Falcon
138
145
  load(full_path)
139
146
  end
140
147
 
141
- Bundler.require(:preload)
148
+ begin
149
+ Bundler.require(:preload)
150
+ rescue Bundler::GemfileNotFound
151
+ # Ignore.
152
+ end
142
153
 
143
154
  if GC.respond_to?(:compact)
144
155
  GC.compact
@@ -29,24 +29,33 @@ require 'async/io/unix_endpoint'
29
29
 
30
30
  module Falcon
31
31
  module Command
32
+ # Implements the `falcon supervisor` command.
33
+ #
34
+ # Talks to an instance of the supervisor to issue commands and print results.
32
35
  class Supervisor < Samovar::Command
33
- self.description = "Control and query a specific host."
36
+ self.description = "Control and query a specific supervisor."
34
37
 
38
+ # The command line options.
39
+ # @attribute [Samovar::Options]
35
40
  options do
36
41
  option "--path <path>", "The control IPC path.", default: "supervisor.ipc"
37
42
  end
38
43
 
44
+ # Implements the `falcon supervisor restart` command.
39
45
  class Restart < Samovar::Command
40
46
  self.description = "Restart the process group."
41
47
 
48
+ # Send the restart message to the supervisor.
42
49
  def call(stream)
43
50
  stream.puts({please: 'restart'}.to_json, separator: "\0")
44
51
  end
45
52
  end
46
53
 
54
+ # Implements the `falcon supervisor metrics` command.
47
55
  class Metrics < Samovar::Command
48
56
  self.description = "Show metrics about the falcon processes."
49
57
 
58
+ # Send the metrics message to the supervisor and print the results.
50
59
  def call(stream)
51
60
  stream.puts({please: 'metrics'}.to_json, separator: "\0")
52
61
  response = JSON.parse(stream.gets("\0"), symbolize_names: true)
@@ -55,15 +64,20 @@ module Falcon
55
64
  end
56
65
  end
57
66
 
67
+ # The nested command to execute.
68
+ # @name nested
69
+ # @attribute [Command]
58
70
  nested :command, {
59
71
  'restart' => Restart,
60
72
  'metrics' => Metrics,
61
73
  }, default: 'metrics'
62
74
 
75
+ # The endpoint the supervisor is bound to.
63
76
  def endpoint
64
77
  Async::IO::Endpoint.unix(@options[:path])
65
78
  end
66
79
 
80
+ # Connect to the supervisor and execute the requested command.
67
81
  def call
68
82
  Async do
69
83
  endpoint.connect do |socket|
@@ -33,9 +33,12 @@ require 'samovar'
33
33
 
34
34
  module Falcon
35
35
  module Command
36
+ # The top level command for the `falcon` executable.
36
37
  class Top < Samovar::Command
37
38
  self.description = "An asynchronous HTTP server."
38
39
 
40
+ # The command line options.
41
+ # @attribute [Samovar::Options]
39
42
  options do
40
43
  option '--verbose | --quiet', "Verbosity of output for debugging.", key: :logging
41
44
  option '-h/--help', "Print out help information."
@@ -43,6 +46,9 @@ module Falcon
43
46
  option '-e/--encoding', "Specify the default external encoding of the server.", default: "UTF-8"
44
47
  end
45
48
 
49
+ # The nested command to execute.
50
+ # @name nested
51
+ # @attribute [Command]
46
52
  nested :command, {
47
53
  'serve' => Serve,
48
54
  'host' => Host,
@@ -52,15 +58,23 @@ module Falcon
52
58
  'supervisor' => Supervisor,
53
59
  }, default: 'serve'
54
60
 
61
+ # Whether verbose logging is enabled.
62
+ # @returns [Boolean]
55
63
  def verbose?
56
64
  @options[:logging] == :verbose
57
65
  end
58
66
 
67
+ # Whether quiet logging was enabled.
68
+ # @returns [Boolean]
59
69
  def quiet?
60
70
  @options[:logging] == :quiet
61
71
  end
62
72
 
73
+ # Update the external encoding.
74
+ #
63
75
  # If you don't specify these, it's possible to have issues when encodings mismatch on the server.
76
+ #
77
+ # @parameter encoding [Encoding] Defaults to `Encoding::UTF_8`.
64
78
  def update_external_encoding!(encoding = Encoding::UTF_8)
65
79
  if Encoding.default_external != encoding
66
80
  Console.logger.warn(self) {"Updating Encoding.default_external from #{Encoding.default_external} to #{encoding}"}
@@ -68,12 +82,14 @@ module Falcon
68
82
  end
69
83
  end
70
84
 
85
+ # The desired external encoding.
71
86
  def encoding
72
87
  if name = @options[:encoding]
73
88
  Encoding.find(name)
74
89
  end
75
90
  end
76
91
 
92
+ # Prepare the environment and invoke the sub-command.
77
93
  def call
78
94
  if encoding = self.encoding
79
95
  update_external_encoding!(encoding)
@@ -27,9 +27,14 @@ require 'samovar'
27
27
 
28
28
  module Falcon
29
29
  module Command
30
+ # Implements the `falcon virtual` command. Designed for *deployment*.
31
+ #
32
+ # Manages a {Controller::Virtual} instance which is responsible for running the {Proxy} and {Redirect} instances.
30
33
  class Virtual < Samovar::Command
31
34
  self.description = "Run one or more virtual hosts with a front-end proxy."
32
35
 
36
+ # The command line options.
37
+ # @attribute [Samovar::Options]
33
38
  options do
34
39
  option '--bind-insecure <address>', "Bind redirection to the given hostname/address", default: "http://[::]:80"
35
40
  option '--bind-secure <address>', "Bind proxy to the given hostname/address", default: "https://[::]:443"
@@ -37,26 +42,34 @@ module Falcon
37
42
  option '-t/--timeout <duration>', "Specify the maximum time to wait for non-blocking operations.", type: Float, default: 30
38
43
  end
39
44
 
45
+ # One or more paths to the configuration files.
46
+ # @name paths
47
+ # @attribute [Array(String)]
40
48
  many :paths
41
49
 
42
50
  include Paths
43
51
 
52
+ # Prepare a new controller for the command.
44
53
  def controller
45
54
  Controller::Virtual.new(self)
46
55
  end
47
56
 
57
+ # The URI to bind the `HTTPS` -> `falcon host` proxy.
48
58
  def bind_secure
49
59
  @options[:bind_secure]
50
60
  end
51
61
 
62
+ # The URI to bind the `HTTP` -> `HTTPS` redirector.
52
63
  def bind_insecure
53
64
  @options[:bind_insecure]
54
65
  end
55
66
 
67
+ # The connection timeout to use for incoming connections.
56
68
  def timeout
57
69
  @options[:timeout]
58
70
  end
59
71
 
72
+ # Prepare the environment and run the controller.
60
73
  def call
61
74
  Async.logger.info(self) do |buffer|
62
75
  buffer.puts "Falcon Virtual v#{VERSION} taking flight!"
@@ -67,10 +80,12 @@ module Falcon
67
80
  self.controller.run
68
81
  end
69
82
 
83
+ # The insecure endpoint for connecting to the {Redirect} instance.
70
84
  def insecure_endpoint(**options)
71
85
  Async::HTTP::Endpoint.parse(@options[:bind_insecure], **options)
72
86
  end
73
87
 
88
+ # The secure endpoint for connecting to the {Proxy} instance.
74
89
  def secure_endpoint(**options)
75
90
  Async::HTTP::Endpoint.parse(@options[:bind_secure], **options)
76
91
  end
@@ -23,13 +23,36 @@
23
23
  require 'build/environment'
24
24
 
25
25
  module Falcon
26
+ # Manages environments which describes how to host a specific application.
27
+ #
28
+ # Environments are key-value maps with lazy value resolution. An environment can inherit from a parent environment, which can provide defaults
29
+ #
30
+ # A typical configuration file might look something like:
31
+ #
32
+ # ~~~ ruby
33
+ # #!/usr/bin/env falcon-host
34
+ # # frozen_string_literal: true
35
+ #
36
+ # load :rack, :self_signed_tls, :supervisor
37
+ #
38
+ # supervisor
39
+ #
40
+ # rack 'hello.localhost', :self_signed_tls do
41
+ # end
42
+ # ~~~
43
+ #
26
44
  class Configuration
27
- def initialize(verbose = false)
45
+ # Initialize an empty configuration.
46
+ def initialize
28
47
  @environments = {}
29
48
  end
30
49
 
50
+ # The map of named environments.
51
+ # @attribute [Hash(String, Build::Environment)]
31
52
  attr :environments
32
53
 
54
+ # Enumerate all environments that have the specified key.
55
+ # @parameter key [Symbol] Filter environments that don't have this key.
33
56
  def each(key = :authority)
34
57
  return to_enum(key) unless block_given?
35
58
 
@@ -42,6 +65,7 @@ module Falcon
42
65
  end
43
66
  end
44
67
 
68
+ # Add the named environment to the configuration.
45
69
  def add(environment)
46
70
  name = environment.name
47
71
 
@@ -56,11 +80,17 @@ module Falcon
56
80
  @environments[name] = environment
57
81
  end
58
82
 
83
+ # Load the specified configuration file. See {Loader#load_file} for more details.
59
84
  def load_file(path)
60
85
  Loader.load_file(self, path)
61
86
  end
62
87
 
88
+ # The domain specific language for loading configuration files.
63
89
  class Loader
90
+ # Initialize the loader, attached to a specific configuration instance.
91
+ # Any environments generated by the loader will be added to the configuration.
92
+ # @parameter configuration [Configuration]
93
+ # @parameter root [String] The file-system root path for relative path computations.
64
94
  def initialize(configuration, root = nil)
65
95
  @loaded = {}
66
96
  @configuration = configuration
@@ -68,9 +98,17 @@ module Falcon
68
98
  @root = root
69
99
  end
70
100
 
71
- attr :path
101
+ # The file-system root path which is injected into the environments as required.
102
+ # @attribute [String]
103
+ attr :root
104
+
105
+ # The attached configuration instance.
106
+ # @attribute [Configuration]
72
107
  attr :configuration
73
108
 
109
+ # Load the specified file into the given configuration.
110
+ # @parameter configuration [Configuration]
111
+ # @oaram path [String] The path to the configuration file, e.g. `falcon.rb`.
74
112
  def self.load_file(configuration, path)
75
113
  path = File.realpath(path)
76
114
  root = File.dirname(path)
@@ -80,11 +118,16 @@ module Falcon
80
118
  loader.instance_eval(File.read(path), path)
81
119
  end
82
120
 
121
+ # Load specific features into the current configuration.
122
+ #
123
+ # Falcon provides default environments for different purposes. These are included in the gem, in the `environments/` directory. This method loads the code in those files into the current configuration.
124
+ #
125
+ # @parameter features [Array(Symbol)] The features to load.
83
126
  def load(*features)
84
127
  features.each do |feature|
85
128
  next if @loaded.include?(feature)
86
129
 
87
- relative_path = File.join(__dir__, "configuration", "#{feature}.rb")
130
+ relative_path = File.join(__dir__, "environments", "#{feature}.rb")
88
131
 
89
132
  self.instance_eval(File.read(relative_path), relative_path)
90
133
 
@@ -92,11 +135,18 @@ module Falcon
92
135
  end
93
136
  end
94
137
 
95
- def add(name, *parents, &block)
138
+ # Add the named environment, with zero or more parent environments, defined using the specified `block`.
139
+ # @parameter name [String] The name of the environment.
140
+ # @parameter parents [Array(Symbol)] The names of the parent environments to inherit.
141
+ # @yields {...} The block that will generate the environment.
142
+ def environment(name, *parents, &block)
96
143
  raise KeyError.new("#{name} is already set", key: name) if @environments.key?(name)
97
144
  @environments[name] = merge(name, *parents, &block)
98
145
  end
99
-
146
+
147
+ # Define a host with the specified name.
148
+ # Adds `root` and `authority` keys.
149
+ # @parameter name [String] The name of the environment, usually a hostname.
100
150
  def host(name, *parents, &block)
101
151
  environment = merge(name, :host, *parents, &block)
102
152
 
@@ -106,6 +156,9 @@ module Falcon
106
156
  @configuration.add(environment.flatten)
107
157
  end
108
158
 
159
+ # Define a proxy with the specified name.
160
+ # Adds `root` and `authority` keys.
161
+ # @parameter name [String] The name of the environment, usually a hostname.
109
162
  def proxy(name, *parents, &block)
110
163
  environment = merge(name, :proxy, *parents, &block)
111
164
 
@@ -115,6 +168,9 @@ module Falcon
115
168
  @configuration.add(environment.flatten)
116
169
  end
117
170
 
171
+ # Define a rack application with the specified name.
172
+ # Adds `root` and `authority` keys.
173
+ # @parameter name [String] The name of the environment, usually a hostname.
118
174
  def rack(name, *parents, &block)
119
175
  environment = merge(name, :rack, *parents, &block)
120
176
 
@@ -124,9 +180,11 @@ module Falcon
124
180
  @configuration.add(environment.flatten)
125
181
  end
126
182
 
127
- def supervisor
183
+ # Define a supervisor instance
184
+ # Adds `root` key.
185
+ def supervisor(&block)
128
186
  name = File.join(@root, "supervisor")
129
- environment = merge(name, :supervisor)
187
+ environment = merge(name, :supervisor, &block)
130
188
 
131
189
  environment[:root] = @root
132
190
 
@@ -135,6 +193,10 @@ module Falcon
135
193
 
136
194
  private
137
195
 
196
+ # Build a new environment with the specified name and the given parents.
197
+ # @parameter name [String]
198
+ # @parameter parents [Array(Build::Environment)]
199
+ # @yields {...} The block that will generate the environment.
138
200
  def merge(name, *parents, &block)
139
201
  environments = parents.map{|name| @environments.fetch(name)}
140
202