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.
@@ -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
@@ -0,0 +1,5 @@
1
+ task :default do
2
+ $LOAD_PATH.unshift(File.expand_path('../lib', __FILE__))
3
+ $LOAD_PATH.unshift(File.expand_path('../test', __FILE__))
4
+ require 'test_helper'
5
+ end
@@ -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