pakyow-core 1.0.0.rc5 → 1.0.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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/lib/pakyow/{environment/actions → actions}/dispatch.rb +0 -0
  4. data/lib/pakyow/{environment/actions → actions}/input_parser.rb +0 -0
  5. data/lib/pakyow/{environment/actions → actions}/logger.rb +0 -0
  6. data/lib/pakyow/{environment/actions → actions}/normalizer.rb +0 -0
  7. data/lib/pakyow/{app.rb → application.rb} +26 -26
  8. data/lib/pakyow/application/behavior/aspects.rb +51 -0
  9. data/lib/pakyow/application/behavior/endpoints.rb +43 -0
  10. data/lib/pakyow/application/behavior/frameworks.rb +47 -0
  11. data/lib/pakyow/application/behavior/helpers.rb +107 -0
  12. data/lib/pakyow/{environment → application}/behavior/initializers.rb +4 -4
  13. data/lib/pakyow/application/behavior/isolating.rb +71 -0
  14. data/lib/pakyow/application/behavior/operations.rb +49 -0
  15. data/lib/pakyow/application/behavior/pipeline.rb +60 -0
  16. data/lib/pakyow/application/behavior/plugins.rb +151 -0
  17. data/lib/pakyow/application/behavior/rescuing.rb +53 -0
  18. data/lib/pakyow/application/behavior/restarting.rb +72 -0
  19. data/lib/pakyow/application/behavior/sessions.rb +38 -0
  20. data/lib/pakyow/{behavior → application}/config.rb +1 -1
  21. data/lib/pakyow/{app → application}/connection.rb +4 -4
  22. data/lib/pakyow/{app → application}/connection/behavior/session.rb +1 -1
  23. data/lib/pakyow/{app → application}/connection/behavior/values.rb +1 -1
  24. data/lib/pakyow/{app → application}/connection/behavior/verifier.rb +1 -1
  25. data/lib/pakyow/{app → application}/connection/session/base.rb +1 -1
  26. data/lib/pakyow/{app → application}/connection/session/cookie.rb +2 -2
  27. data/lib/pakyow/application/helpers/app.rb +30 -0
  28. data/lib/pakyow/application/helpers/connection.rb +47 -0
  29. data/lib/pakyow/behavior/initializers.rb +3 -3
  30. data/lib/pakyow/behavior/input_parsing.rb +55 -0
  31. data/lib/pakyow/behavior/plugins.rb +3 -130
  32. data/lib/pakyow/behavior/restarting.rb +28 -46
  33. data/lib/pakyow/behavior/running.rb +127 -0
  34. data/lib/pakyow/behavior/silencing.rb +21 -0
  35. data/lib/pakyow/behavior/timezone.rb +19 -0
  36. data/lib/pakyow/behavior/verification.rb +1 -1
  37. data/lib/pakyow/behavior/verifier.rb +30 -0
  38. data/lib/pakyow/behavior/watching.rb +73 -0
  39. data/lib/pakyow/config.rb +168 -0
  40. data/lib/pakyow/environment.rb +31 -31
  41. data/lib/pakyow/helper.rb +9 -0
  42. data/lib/pakyow/loader.rb +7 -1
  43. data/lib/pakyow/plugin.rb +22 -21
  44. metadata +42 -42
  45. data/lib/pakyow/behavior/aspects.rb +0 -49
  46. data/lib/pakyow/behavior/endpoints.rb +0 -41
  47. data/lib/pakyow/behavior/frameworks.rb +0 -45
  48. data/lib/pakyow/behavior/helpers.rb +0 -108
  49. data/lib/pakyow/behavior/isolating.rb +0 -69
  50. data/lib/pakyow/behavior/operations.rb +0 -47
  51. data/lib/pakyow/behavior/pipeline.rb +0 -58
  52. data/lib/pakyow/behavior/rescuing.rb +0 -51
  53. data/lib/pakyow/behavior/sessions.rb +0 -36
  54. data/lib/pakyow/environment/behavior/config.rb +0 -172
  55. data/lib/pakyow/environment/behavior/input_parsing.rb +0 -57
  56. data/lib/pakyow/environment/behavior/plugins.rb +0 -23
  57. data/lib/pakyow/environment/behavior/restarting.rb +0 -54
  58. data/lib/pakyow/environment/behavior/running.rb +0 -129
  59. data/lib/pakyow/environment/behavior/silencing.rb +0 -23
  60. data/lib/pakyow/environment/behavior/timezone.rb +0 -21
  61. data/lib/pakyow/environment/behavior/verifier.rb +0 -32
  62. data/lib/pakyow/environment/behavior/watching.rb +0 -75
  63. data/lib/pakyow/helpers/app.rb +0 -28
  64. data/lib/pakyow/helpers/connection.rb +0 -45
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pakyow/support/extension"
4
+
5
+ require "pakyow/operation"
6
+
7
+ module Pakyow
8
+ class Application
9
+ module Behavior
10
+ # Adds support for operations.
11
+ #
12
+ module Operations
13
+ class Lookup
14
+ def initialize(operations:, app:)
15
+ operations.each do |operation|
16
+ define_singleton_method operation.__object_name.name do |values = {}, &block|
17
+ (block ? Class.new(operation, &block) : operation).new(app: app, **values).perform
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ extend Support::Extension
24
+
25
+ apply_extension do
26
+ on "load" do
27
+ load_aspect(:operations)
28
+ end
29
+
30
+ attr_reader :operations
31
+ after "initialize" do
32
+ @operations = Lookup.new(operations: state(:operation), app: self)
33
+ end
34
+ end
35
+
36
+ class_methods do
37
+ # Define operations as stateful when an app is defined.
38
+ #
39
+ # @api private
40
+ def make(*)
41
+ super.tap do |new_class|
42
+ new_class.stateful :operation, Operation
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pakyow/support/extension"
4
+
5
+ module Pakyow
6
+ class Application
7
+ module Behavior
8
+ # Loads default pipeline actions based on included frameworks.
9
+ #
10
+ module Pipeline
11
+ extend Support::Extension
12
+
13
+ apply_extension do
14
+ # We set the priority very low here in case initialize hooks in other frameworks define
15
+ # state that should be loaded into the pipeline (e.g. controllers).
16
+ #
17
+ after "initialize", "initialize.pipeline", priority: -10 do
18
+ self.class.__pipeline.dup.tap do |pipeline|
19
+ load_pipeline_defaults(pipeline)
20
+ @__pipeline = pipeline.callable(self)
21
+ end
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def load_pipeline_defaults(pipeline)
28
+ if self.class.includes_framework?(:assets)
29
+ pipeline.action(Actions::Assets::Public, self)
30
+ pipeline.action(Actions::Assets::Process)
31
+ end
32
+
33
+ if self.class.includes_framework?(:realtime) && Pakyow.config.realtime.server && !is_a?(Plugin)
34
+ pipeline.action(Actions::Realtime::Upgrader)
35
+ end
36
+
37
+ if self.class.includes_framework?(:routing) && !Pakyow.env?(:prototype)
38
+ state(:controller).each do |controller|
39
+ pipeline.action(controller, self)
40
+ end
41
+ end
42
+
43
+ if instance_variable_defined?(:@plugs)
44
+ @plugs.each do |plug_instance|
45
+ pipeline.action(plug_instance)
46
+ end
47
+ end
48
+
49
+ if self.class.includes_framework?(:presenter)
50
+ pipeline.action(Actions::Presenter::AutoRender)
51
+ end
52
+
53
+ if self.class.includes_framework?(:routing) && !Pakyow.env?(:prototype) && !is_a?(Plugin)
54
+ pipeline.action(Actions::Routing::RespondMissing)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pakyow/errors"
4
+
5
+ require "pakyow/support/deep_dup"
6
+ require "pakyow/support/extension"
7
+
8
+ require "pakyow/plugin/lookup"
9
+
10
+ module Pakyow
11
+ class Application
12
+ module Behavior
13
+ # @api private
14
+ module Plugins
15
+ extend Support::Extension
16
+
17
+ using Support::DeepDup
18
+
19
+ attr_reader :plugs
20
+
21
+ def plug(name, instance = :default)
22
+ @plugs.find { |plug|
23
+ plug.class.plugin_name == name && plug.class.__object_name.namespace.parts.last == instance
24
+ }
25
+ end
26
+
27
+ apply_extension do
28
+ class_state :__plugs, default: [], inheritable: true
29
+
30
+ # Create a dynamic helper that allows plugin helpers to be called in context of a specific plug.
31
+ #
32
+ on "initialize" do
33
+ self.class.register_helper :passive, Module.new {
34
+ Pakyow.plugins.keys.map.each do |plugin_name|
35
+ define_method plugin_name do |plug = :default|
36
+ app.plugs.send(plugin_name, plug).helper_caller(
37
+ app.class.included_helper_context(self),
38
+ @connection,
39
+ self
40
+ )
41
+ end
42
+ end
43
+ }
44
+ end
45
+
46
+ # Setting priority to low gives the app a chance to do any pre-loading
47
+ # that might affect how plugins are setup.
48
+ #
49
+ after "initialize", "load.plugins", priority: :low do
50
+ @plugs = Plugin::Lookup.new([])
51
+
52
+ self.class.__plugs.each do |plug|
53
+ if self.class.includes_framework?(:presenter)
54
+ require "pakyow/plugin/helpers/presenter/rendering"
55
+ plug.register_helper :passive, Plugin::Helpers::Presenter::Rendering
56
+ end
57
+
58
+ # Include frameworks from app.
59
+ #
60
+ plug.include_frameworks(
61
+ *self.class.config.loaded_frameworks
62
+ )
63
+
64
+ # Copy settings from the app config.
65
+ #
66
+ plug.config.instance_variable_set(
67
+ :@__settings, config.__settings.deep_dup.merge(plug.config.__settings)
68
+ )
69
+
70
+ # Copy defaults from the app config.
71
+ #
72
+ plug.config.instance_variable_set(
73
+ :@__defaults, config.__defaults.deep_dup.merge(plug.config.__defaults)
74
+ )
75
+
76
+ # Copy groups from the app config.
77
+ #
78
+ plug.config.instance_variable_set(
79
+ :@__groups, config.__groups.deep_dup.merge(plug.config.__groups)
80
+ )
81
+
82
+ # Override config values that require a specific value.
83
+ #
84
+ full_name = [plug.plugin_name]
85
+ unless plug.__object_name.namespace.parts.last == :default
86
+ full_name << plug.__object_name.namespace.parts.last
87
+ end
88
+
89
+ plug.config.name = full_name.join("_").to_sym
90
+
91
+ # Create a dynamic helper that allows plugin helpers to be called in context of a specific plug.
92
+ #
93
+ plug.register_helper :passive, Module.new {
94
+ Pakyow.plugins.keys.map.each do |plugin_name|
95
+ define_method plugin_name do |instance_name = :default|
96
+ app.parent.plugs.send(plugin_name, instance_name).helper_caller(
97
+ app.class.included_helper_context(self),
98
+ @connection,
99
+ self
100
+ )
101
+ end
102
+ end
103
+ }
104
+
105
+ # Finally, create the plugin instance.
106
+ #
107
+ @plugs << plug.new(self)
108
+ end
109
+
110
+ @plugs.finalize
111
+ end
112
+
113
+ after "boot" do
114
+ @plugs.each(&:booted)
115
+ end
116
+ end
117
+
118
+ class_methods do
119
+ attr_reader :__plugs
120
+
121
+ def plug(plugin_name, at: "/", as: :default, &block)
122
+ plugin_name = plugin_name.to_sym
123
+
124
+ unless plugin = Pakyow.plugins[plugin_name]
125
+ raise UnknownPlugin.new_with_message(
126
+ plugin: plugin_name
127
+ )
128
+ end
129
+
130
+ app = self
131
+ plug = plugin.make(
132
+ "plug",
133
+ within: Support::ObjectNamespace.new(
134
+ *__object_name.namespace.parts + [plugin_name, as]
135
+ ),
136
+ mount_path: at,
137
+ ) do
138
+ # Creates a connection subclass that other frameworks can safely extend.
139
+ #
140
+ isolate(app.isolated(:Connection))
141
+
142
+ instance_exec(&block) if block
143
+ end
144
+
145
+ @__plugs << plug
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pakyow/support/extension"
4
+
5
+ module Pakyow
6
+ class Application
7
+ module Behavior
8
+ # Lets an app to be rescued from errors encountered during boot. Once rescued,
9
+ # an app returns a 500 response with the error that caused it to fail.
10
+ #
11
+ module Rescuing
12
+ extend Support::Extension
13
+
14
+ # Error the app was rescued from.
15
+ #
16
+ attr_reader :rescued
17
+
18
+ # Returns true if the app has been rescued.
19
+ #
20
+ def rescued?
21
+ instance_variable_defined?(:@rescued) && !!@rescued
22
+ end
23
+
24
+ private
25
+
26
+ # Enters rescue mode after logging the error.
27
+ #
28
+ def rescue!(error)
29
+ @rescued = error
30
+
31
+ performing :rescue do
32
+ Pakyow.logger.error(error)
33
+
34
+ message = <<~ERROR
35
+ #{self.class} failed to initialize.
36
+
37
+ #{error.message}
38
+ #{error.backtrace.join("\n")}
39
+ ERROR
40
+
41
+ # Override call to always return an errored response.
42
+ #
43
+ define_singleton_method :call do |connection|
44
+ connection.status = 500
45
+ connection.body = StringIO.new(message)
46
+ connection.halt
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+
5
+ require "pakyow/support/silenceable"
6
+ Pakyow::Support::Silenceable.silence_warnings do
7
+ require "filewatcher"
8
+ end
9
+
10
+ require "pakyow/support/extension"
11
+
12
+ module Pakyow
13
+ class Application
14
+ module Behavior
15
+ # Handles triggering restarts in the parent process.
16
+ #
17
+ module Restarting
18
+ extend Support::Extension
19
+
20
+ apply_extension do
21
+ configurable :process do
22
+ setting :watched_paths, []
23
+ setting :excluded_paths, []
24
+ setting :restartable, false
25
+
26
+ defaults :development do
27
+ setting :restartable, true
28
+ end
29
+
30
+ defaults :prototype do
31
+ setting :restartable, true
32
+ end
33
+ end
34
+
35
+ after "initialize" do
36
+ setup_for_restarting
37
+ end
38
+
39
+ # Setting up for restarting even after the app fails to initialize lets
40
+ # the developer fix the problem and let the server restart on its own.
41
+ #
42
+ after "rescue" do
43
+ setup_for_restarting
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def setup_for_restarting
50
+ if config.process.restartable
51
+ config.process.watched_paths << File.join(config.src, "**/*.rb")
52
+ config.process.watched_paths << File.join(config.lib, "**/*.rb")
53
+
54
+ # FIXME: this doesn't need to be hardcoded, but instead determined
55
+ # from the source location when registered with the environment
56
+ config.process.watched_paths << "./config/application.rb"
57
+
58
+ Thread.new do
59
+ Filewatcher.new(
60
+ config.process.watched_paths,
61
+ exclude: config.process.excluded_paths
62
+ ).watch do |_path, _event|
63
+ FileUtils.mkdir_p "./tmp"
64
+ FileUtils.touch "./tmp/restart.txt"
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pakyow/support/extension"
4
+ require "pakyow/support/inflector"
5
+
6
+ module Pakyow
7
+ class Application
8
+ module Behavior
9
+ module Sessions
10
+ extend Support::Extension
11
+
12
+ apply_extension do
13
+ attr_reader :session_object, :session_options
14
+
15
+ after "configure" do
16
+ if config.session.enabled
17
+ require "pakyow/application/connection/session/#{config.session.object}"
18
+
19
+ @session_object = Pakyow::Application::Connection::Session.const_get(
20
+ Support.inflector.classify(config.session.object)
21
+ )
22
+
23
+ @session_options = if config.session.respond_to?(config.session.object)
24
+ config.session.public_send(config.session.object)
25
+ else
26
+ {}
27
+ end
28
+ end
29
+ rescue LoadError => error
30
+ # TODO: Improve this with a specific "session object missing" error.
31
+ #
32
+ raise error
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -4,7 +4,7 @@ require "pakyow/support/extension"
4
4
  require "pakyow/support/path_version"
5
5
 
6
6
  module Pakyow
7
- module Behavior
7
+ class Application
8
8
  module Config
9
9
  extend Support::Extension
10
10
 
@@ -5,16 +5,16 @@ require "delegate"
5
5
  require "pakyow/support/hookable"
6
6
 
7
7
  module Pakyow
8
- class App
8
+ class Application
9
9
  class Connection < SimpleDelegator
10
10
  attr_reader :app
11
11
 
12
12
  include Support::Hookable
13
13
  events :initialize, :dup
14
14
 
15
- require "pakyow/app/connection/behavior/session"
16
- require "pakyow/app/connection/behavior/verifier"
17
- require "pakyow/app/connection/behavior/values"
15
+ require "pakyow/application/connection/behavior/session"
16
+ require "pakyow/application/connection/behavior/verifier"
17
+ require "pakyow/application/connection/behavior/values"
18
18
 
19
19
  include Behavior::Session
20
20
  include Behavior::Verifier