moonrope 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.
- checksums.yaml +7 -0
- data/Rakefile +5 -0
- data/lib/moonrope.rb +37 -0
- data/lib/moonrope/action.rb +163 -0
- data/lib/moonrope/action_result.rb +63 -0
- data/lib/moonrope/base.rb +130 -0
- data/lib/moonrope/before_action.rb +24 -0
- data/lib/moonrope/controller.rb +49 -0
- data/lib/moonrope/dsl/action_dsl.rb +70 -0
- data/lib/moonrope/dsl/base_dsl.rb +74 -0
- data/lib/moonrope/dsl/controller_dsl.rb +57 -0
- data/lib/moonrope/dsl/structure_dsl.rb +63 -0
- data/lib/moonrope/dsl/structure_restriction_dsl.rb +27 -0
- data/lib/moonrope/errors.rb +48 -0
- data/lib/moonrope/eval_environment.rb +141 -0
- data/lib/moonrope/eval_helpers.rb +35 -0
- data/lib/moonrope/helper.rb +28 -0
- data/lib/moonrope/param_set.rb +44 -0
- data/lib/moonrope/rack_middleware.rb +73 -0
- data/lib/moonrope/railtie.rb +30 -0
- data/lib/moonrope/request.rb +165 -0
- data/lib/moonrope/structure.rb +83 -0
- data/lib/moonrope/version.rb +3 -0
- metadata +152 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 89677af83c79db9270d024635bb4a4cefc8131f6
|
4
|
+
data.tar.gz: 0a4002afcef30a933974d0090c501f276f0bd13d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8e4a4fc0d9bd542697910e6c82e72faa41debf0cf2f6497267ab036d681bd28ca9dddd0079bbf0c5e868bca224e6728e46ce398bf7ae3c65e3809ed10b66e7fe
|
7
|
+
data.tar.gz: d974dffc746c61c3a5f5543ca21f22849c82020fe324e90a1e549479b6dcac9a1f096cef8f7a3f7d7b5455819df0db931ca40498e73ceeae9d3a4db7e33dec50
|
data/Rakefile
ADDED
data/lib/moonrope.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
require 'moonrope/action'
|
5
|
+
require 'moonrope/action_result'
|
6
|
+
require 'moonrope/base'
|
7
|
+
require 'moonrope/before_action'
|
8
|
+
require 'moonrope/controller'
|
9
|
+
require 'moonrope/dsl/base_dsl'
|
10
|
+
require 'moonrope/dsl/action_dsl'
|
11
|
+
require 'moonrope/dsl/controller_dsl'
|
12
|
+
require 'moonrope/dsl/structure_dsl'
|
13
|
+
require 'moonrope/dsl/structure_restriction_dsl'
|
14
|
+
|
15
|
+
require 'moonrope/errors'
|
16
|
+
require 'moonrope/eval_helpers'
|
17
|
+
require 'moonrope/eval_environment'
|
18
|
+
require 'moonrope/helper'
|
19
|
+
require 'moonrope/param_set'
|
20
|
+
require 'moonrope/rack_middleware'
|
21
|
+
require 'moonrope/request'
|
22
|
+
require 'moonrope/structure'
|
23
|
+
require 'moonrope/version'
|
24
|
+
|
25
|
+
require 'moonrope/railtie' if defined?(Rails)
|
26
|
+
|
27
|
+
module Moonrope
|
28
|
+
|
29
|
+
class << self
|
30
|
+
attr_accessor :logger
|
31
|
+
|
32
|
+
def logger
|
33
|
+
@logger ||= Logger.new(STDOUT)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
module Moonrope
|
2
|
+
class Action
|
3
|
+
|
4
|
+
# @return [Moonrope::Controller] the associated controller
|
5
|
+
attr_reader :controller
|
6
|
+
|
7
|
+
# @return [Symbol] the name of the action
|
8
|
+
attr_reader :name
|
9
|
+
|
10
|
+
# @return [Moonrope::DSL::Action] the action's DSL
|
11
|
+
attr_reader :dsl
|
12
|
+
|
13
|
+
# @return [Hash] the params available for the action
|
14
|
+
attr_reader :params
|
15
|
+
|
16
|
+
# @return [String] the description of the action
|
17
|
+
attr_accessor :description
|
18
|
+
|
19
|
+
# @return [Proc] the access check condition for the action
|
20
|
+
attr_accessor :access
|
21
|
+
|
22
|
+
# @return [Proc] the action for the action
|
23
|
+
attr_accessor :action
|
24
|
+
|
25
|
+
#
|
26
|
+
# Initialize a new action
|
27
|
+
#
|
28
|
+
# @param controller [Moonrope::Controller] the controller this action belongs to
|
29
|
+
# @param name [Symbol] the name of the action
|
30
|
+
# @yield allows the action to be configured via Moonrope::DSL::ActionDSL
|
31
|
+
#
|
32
|
+
def initialize(controller, name, &block)
|
33
|
+
@controller = controller
|
34
|
+
@name = name
|
35
|
+
@params = {}
|
36
|
+
@dsl = Moonrope::DSL::ActionDSL.new(self)
|
37
|
+
@dsl.instance_eval(&block) if block_given?
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# Return a hash of all params for this action which are
|
42
|
+
#
|
43
|
+
# @return [Hash] hash with field names as keys with default values
|
44
|
+
#
|
45
|
+
def default_params
|
46
|
+
@params.inject({}) do |h,(k,v)|
|
47
|
+
h[k.to_s] = v[:default] if v[:default]
|
48
|
+
h
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Executes the action and returns a ActionResult object with the result
|
54
|
+
# of the action.
|
55
|
+
#
|
56
|
+
# @param request [Moonrope::Request or Moonrope::EvalEnvironment]
|
57
|
+
# @return [Moonrope::ActionResult]
|
58
|
+
#
|
59
|
+
def execute(request = nil)
|
60
|
+
if request.is_a?(EvalEnvironment)
|
61
|
+
eval_environment = request
|
62
|
+
else
|
63
|
+
eval_environment = EvalEnvironment.new(@controller.base, request)
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# Set this actions default parameters in the eval environment so that
|
68
|
+
# it has access to them.
|
69
|
+
#
|
70
|
+
eval_environment.default_params = self.default_params
|
71
|
+
|
72
|
+
#
|
73
|
+
# Set the current action to the eval environment so it knows what action
|
74
|
+
# invoked this.
|
75
|
+
#
|
76
|
+
eval_environment.action = self
|
77
|
+
|
78
|
+
begin
|
79
|
+
#
|
80
|
+
# Validate the parameters
|
81
|
+
#
|
82
|
+
self.validate_parameters(eval_environment.params)
|
83
|
+
|
84
|
+
start_time = Time.now
|
85
|
+
|
86
|
+
# Run before filters
|
87
|
+
controller.before_actions_for(name).each do |action|
|
88
|
+
eval_environment.instance_eval(&action.block)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Run the actual action
|
92
|
+
response = eval_environment.instance_eval(&action)
|
93
|
+
|
94
|
+
# Calculate the length of time this request takes
|
95
|
+
time_to_run = Time.now - start_time
|
96
|
+
|
97
|
+
# Prepare a action result
|
98
|
+
result = ActionResult.new(self)
|
99
|
+
result.data = response
|
100
|
+
result.status = 'success'
|
101
|
+
result.time = time_to_run.round(2)
|
102
|
+
result.flags = eval_environment.flags
|
103
|
+
result.headers = eval_environment.headers
|
104
|
+
|
105
|
+
# Return the result object
|
106
|
+
result
|
107
|
+
|
108
|
+
rescue Moonrope::Errors::RequestError => e
|
109
|
+
result = ActionResult.new(self)
|
110
|
+
result.status = e.status
|
111
|
+
result.data = e.data
|
112
|
+
result
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
#
|
117
|
+
# Check whether the authenticated user has access to this request.
|
118
|
+
# Accepts a Request or an EvalEnvironment.
|
119
|
+
#
|
120
|
+
# @param request [Moonrope::Request or Moonrope::EvalEnvironment]
|
121
|
+
# @return [Boolean]
|
122
|
+
#
|
123
|
+
def check_access(request = nil)
|
124
|
+
if request.is_a?(EvalEnvironment)
|
125
|
+
eval_environment = request
|
126
|
+
else
|
127
|
+
eval_environment = EvalEnvironment.new(@controller.base, request)
|
128
|
+
end
|
129
|
+
|
130
|
+
if eval_environment.auth && access.is_a?(Proc)
|
131
|
+
!!eval_environment.instance_eval(&access)
|
132
|
+
elsif @controller.base.default_access.is_a?(Proc)
|
133
|
+
!!eval_environment.instance_exec(self, &@controller.base.default_access)
|
134
|
+
else
|
135
|
+
false
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
#
|
140
|
+
# Return whether or not the passed ParamSet is valid for this action
|
141
|
+
#
|
142
|
+
# @param param_set [Moonrope::ParamSet] the param set to check
|
143
|
+
# @return [Boolean]
|
144
|
+
#
|
145
|
+
def validate_parameters(param_set)
|
146
|
+
@params.each do |name, value|
|
147
|
+
if value[:required] && param_set[name].nil?
|
148
|
+
raise Moonrope::Errors::ParameterError, "`#{name}` parameter is required but is missing"
|
149
|
+
end
|
150
|
+
|
151
|
+
if value[:regex] && param_set[name] && !(param_set[name].to_s =~ value[:regex])
|
152
|
+
raise Moonrope::Errors::ParameterError, "`#{name}` parameter is invalid"
|
153
|
+
end
|
154
|
+
|
155
|
+
if value[:type] && param_set[name] && !param_set[name].is_a?(value[:type])
|
156
|
+
raise Moonrope::Errors::ParameterError, "`#{name}` should be a `#{value[:type]}` but is a `#{param_set[name].class}`"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
true
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Moonrope
|
2
|
+
class ActionResult
|
3
|
+
|
4
|
+
#
|
5
|
+
# Initialize a new result from a Moonrope::Action.
|
6
|
+
#
|
7
|
+
# @param action [Moonrope::Action] the action which originated this result
|
8
|
+
#
|
9
|
+
def initialize(action)
|
10
|
+
@action = action
|
11
|
+
@headers = {}
|
12
|
+
@time = nil
|
13
|
+
@flags = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return [Object] the return value from the action
|
17
|
+
attr_accessor :data
|
18
|
+
|
19
|
+
# @return [String] the status of the request
|
20
|
+
attr_accessor :status
|
21
|
+
|
22
|
+
# @return [Hash] headers which have been set in the action
|
23
|
+
attr_accessor :headers
|
24
|
+
|
25
|
+
# @return [Float] the length of time to process the action
|
26
|
+
attr_accessor :time
|
27
|
+
|
28
|
+
# @return [Hash] flags which have been set in the action
|
29
|
+
attr_accessor :flags
|
30
|
+
|
31
|
+
#
|
32
|
+
# Return a Hash representation of this ActionResult without the
|
33
|
+
# headers.
|
34
|
+
#
|
35
|
+
# {
|
36
|
+
# :status => 'success',
|
37
|
+
# :time => 1.32,
|
38
|
+
# :flags => {},
|
39
|
+
# :data => {}
|
40
|
+
# }
|
41
|
+
#
|
42
|
+
# @return [Hash]
|
43
|
+
#
|
44
|
+
def to_hash
|
45
|
+
{
|
46
|
+
:status => self.status,
|
47
|
+
:time => self.time,
|
48
|
+
:flags => self.flags,
|
49
|
+
:data => self.data
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# Return the ActionResult's hash with a JSON.
|
55
|
+
#
|
56
|
+
# @return [String]
|
57
|
+
#
|
58
|
+
def to_json
|
59
|
+
to_hash.to_json
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module Moonrope
|
2
|
+
class Base
|
3
|
+
|
4
|
+
#
|
5
|
+
# Load a set of Moonrope configuration files from a given
|
6
|
+
# directory.
|
7
|
+
#
|
8
|
+
# @param path [String] the path to a directory containing Moonrope files
|
9
|
+
# @return [Moonrope::Base]
|
10
|
+
#
|
11
|
+
def self.load(path)
|
12
|
+
api = self.new
|
13
|
+
api.load(path)
|
14
|
+
api
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [Array] the array of defined structures
|
18
|
+
attr_reader :structures
|
19
|
+
|
20
|
+
# @return [Array] the array of defined controllers
|
21
|
+
attr_accessor :controllers
|
22
|
+
|
23
|
+
# @return [Array] the array of defined helpers
|
24
|
+
attr_accessor :helpers
|
25
|
+
|
26
|
+
# @return [Moonrope::DSL::BaseDSL] the base DSL
|
27
|
+
attr_accessor :dsl
|
28
|
+
|
29
|
+
# @return [Proc] the authentictor
|
30
|
+
attr_accessor :authenticator
|
31
|
+
|
32
|
+
# @return [Proc] the default access condition
|
33
|
+
attr_accessor :default_access
|
34
|
+
|
35
|
+
# @return [String] the directory the base was loaded from (if relevant)
|
36
|
+
attr_accessor :loaded_from
|
37
|
+
|
38
|
+
#
|
39
|
+
# Initialize a new instance of the Moonrope::Base
|
40
|
+
#
|
41
|
+
# @yield instance evals the contents within the Base DSL
|
42
|
+
#
|
43
|
+
def initialize(&block)
|
44
|
+
unload
|
45
|
+
@dsl = Moonrope::DSL::BaseDSL.new(self)
|
46
|
+
@dsl.instance_eval(&block) if block_given?
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# Reset the whole base to contain no data.
|
51
|
+
#
|
52
|
+
def unload
|
53
|
+
@structures = []
|
54
|
+
@controllers = []
|
55
|
+
@helpers = []
|
56
|
+
@authenticator = nil
|
57
|
+
@default_access = nil
|
58
|
+
end
|
59
|
+
|
60
|
+
#
|
61
|
+
# Reload this whole base API from the path
|
62
|
+
#
|
63
|
+
def load(directory = nil)
|
64
|
+
directory = self.loaded_from if directory.nil?
|
65
|
+
if directory
|
66
|
+
unload
|
67
|
+
Dir["#{directory}/**/*.rb"].each do |filename|
|
68
|
+
self.dsl.instance_eval(File.read(filename), filename)
|
69
|
+
end
|
70
|
+
self.loaded_from = directory
|
71
|
+
self
|
72
|
+
else
|
73
|
+
raise Moonrope::Error, "Can't reload Moonrope::Base as it wasn't required from a directory"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
alias_method :reload, :load
|
78
|
+
|
79
|
+
#
|
80
|
+
# Return a structure of the given name
|
81
|
+
#
|
82
|
+
# @param name [Symbol] the name of the structure
|
83
|
+
# @return [Moonrope::Structure]
|
84
|
+
#
|
85
|
+
def structure(name)
|
86
|
+
structures.select { |s| s.name == name }.first
|
87
|
+
end
|
88
|
+
|
89
|
+
alias_method :[], :structure
|
90
|
+
|
91
|
+
#
|
92
|
+
# Return a controller of the given name
|
93
|
+
#
|
94
|
+
# @param name [Symbol] the name of the controller
|
95
|
+
# @return [Moonrope::Controller]
|
96
|
+
#
|
97
|
+
def controller(name)
|
98
|
+
controllers.select { |a| a.name == name }.first
|
99
|
+
end
|
100
|
+
|
101
|
+
alias_method :/, :controller
|
102
|
+
|
103
|
+
#
|
104
|
+
# Create a new rack request for this API.
|
105
|
+
#
|
106
|
+
# @return [Moonrope::Request] a new request object
|
107
|
+
#
|
108
|
+
def request(*args)
|
109
|
+
Moonrope::Request.new(self, *args)
|
110
|
+
end
|
111
|
+
|
112
|
+
#
|
113
|
+
# Return a helper for the given name and, potentially controller
|
114
|
+
#
|
115
|
+
# @param name [Symbol] the name of the helper
|
116
|
+
# @param controller [Moonrope::Controller] the controller scope
|
117
|
+
#
|
118
|
+
def helper(name, controller = nil)
|
119
|
+
if controller
|
120
|
+
matched_helpers = @helpers.select do |h|
|
121
|
+
h.name == name.to_sym && (h.controller.nil? || h.controller == controller)
|
122
|
+
end
|
123
|
+
else
|
124
|
+
matched_helpers = @helpers.select { |h| h.name == name.to_sym && h.controller.nil? }
|
125
|
+
end
|
126
|
+
matched_helpers.first
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Moonrope
|
2
|
+
class BeforeAction
|
3
|
+
|
4
|
+
# @return [Array] the names of actions to execute this request on
|
5
|
+
attr_accessor :actions
|
6
|
+
|
7
|
+
# @return [Proc] the block to execute in this action
|
8
|
+
attr_accessor :block
|
9
|
+
|
10
|
+
# @return [Moonrope::Controller] the associated controller
|
11
|
+
attr_reader :controller
|
12
|
+
|
13
|
+
#
|
14
|
+
# Initilize a new BeforeAction
|
15
|
+
#
|
16
|
+
# @param controller [Moonrope::Controller]
|
17
|
+
#
|
18
|
+
def initialize(controller)
|
19
|
+
@controller = controller
|
20
|
+
@actions = []
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Moonrope
|
2
|
+
class Controller
|
3
|
+
|
4
|
+
attr_accessor :name, :actions, :befores
|
5
|
+
attr_reader :base, :dsl
|
6
|
+
|
7
|
+
#
|
8
|
+
# Initalize a new Moonrope::Controller
|
9
|
+
#
|
10
|
+
# @param base [Moonrope::Base] the base
|
11
|
+
# @param name [Symbol] the name of the controller
|
12
|
+
# @yield instance evals the contents within the ControllerDSL
|
13
|
+
#
|
14
|
+
def initialize(base, name, &block)
|
15
|
+
@base = base
|
16
|
+
@name = name
|
17
|
+
@actions = {}
|
18
|
+
@befores = []
|
19
|
+
@dsl = Moonrope::DSL::ControllerDSL.new(self)
|
20
|
+
@dsl.instance_eval(&block) if block_given?
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# Return an array of before actions which must be executed for
|
25
|
+
# the given action.
|
26
|
+
#
|
27
|
+
# @param action [Symbol] the name of the action to return
|
28
|
+
# @return [Array] an array of Moonrope::BeforeAction instances
|
29
|
+
#
|
30
|
+
def before_actions_for(action)
|
31
|
+
@befores.select do |b|
|
32
|
+
b.actions.empty? || b.actions.include?(action)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Lookup and return an action in this controller by name.
|
38
|
+
#
|
39
|
+
# @param action [Symbol] the name of the action
|
40
|
+
# @return [Moonrope::Action] the action
|
41
|
+
#
|
42
|
+
def action(action)
|
43
|
+
actions[action.to_sym]
|
44
|
+
end
|
45
|
+
|
46
|
+
alias_method :/, :action
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|