pakyow-core 1.0.0.rc5 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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