moonrope 1.4.1 → 2.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 +4 -4
- data/Gemfile +9 -0
- data/Gemfile.lock +47 -0
- data/MIT-LICENCE +20 -0
- data/README.md +24 -0
- data/bin/moonrope +28 -0
- data/docs/authentication.md +114 -0
- data/docs/controllers.md +106 -0
- data/docs/exceptions.md +27 -0
- data/docs/introduction.md +29 -0
- data/docs/structures.md +214 -0
- data/example/authentication.rb +50 -0
- data/example/controllers/meta_controller.rb +14 -0
- data/example/controllers/users_controller.rb +92 -0
- data/example/structures/pet_structure.rb +12 -0
- data/example/structures/user_structure.rb +35 -0
- data/html/assets/lock.svg +3 -0
- data/html/assets/reset.css +101 -0
- data/html/assets/style.css +348 -0
- data/html/assets/tool.svg +4 -0
- data/html/assets/try.js +151 -0
- data/html/authenticators/default.html +191 -0
- data/html/controllers/meta/version.html +144 -0
- data/html/controllers/meta.html +73 -0
- data/html/controllers/users/create.html +341 -0
- data/html/controllers/users/list.html +348 -0
- data/html/controllers/users/show.html +261 -0
- data/html/controllers/users/update.html +387 -0
- data/html/controllers/users.html +93 -0
- data/html/index.html +166 -0
- data/html/moonrope.txt +0 -0
- data/html/structures/pet.html +176 -0
- data/html/structures/user.html +338 -0
- data/lib/moonrope/action.rb +165 -37
- data/lib/moonrope/authenticator.rb +39 -0
- data/lib/moonrope/base.rb +24 -6
- data/lib/moonrope/controller.rb +4 -2
- data/lib/moonrope/doc_context.rb +94 -0
- data/lib/moonrope/doc_server.rb +123 -0
- data/lib/moonrope/dsl/action_dsl.rb +159 -9
- data/lib/moonrope/dsl/authenticator_dsl.rb +31 -0
- data/lib/moonrope/dsl/base_dsl.rb +21 -18
- data/lib/moonrope/dsl/controller_dsl.rb +60 -9
- data/lib/moonrope/dsl/filterable_dsl.rb +27 -0
- data/lib/moonrope/dsl/structure_dsl.rb +27 -2
- data/lib/moonrope/errors.rb +3 -0
- data/lib/moonrope/eval_environment.rb +82 -3
- data/lib/moonrope/eval_helpers/filter_helper.rb +82 -0
- data/lib/moonrope/eval_helpers.rb +28 -5
- data/lib/moonrope/guard.rb +35 -0
- data/lib/moonrope/html_generator.rb +65 -0
- data/lib/moonrope/param_set.rb +11 -1
- data/lib/moonrope/rack_middleware.rb +1 -1
- data/lib/moonrope/railtie.rb +31 -14
- data/lib/moonrope/request.rb +25 -14
- data/lib/moonrope/structure.rb +74 -11
- data/lib/moonrope/structure_attribute.rb +15 -0
- data/lib/moonrope/version.rb +1 -1
- data/lib/moonrope.rb +5 -4
- data/moonrope.gemspec +21 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/specs/action_spec.rb +455 -0
- data/spec/specs/base_spec.rb +29 -0
- data/spec/specs/controller_spec.rb +31 -0
- data/spec/specs/param_set_spec.rb +31 -0
- data/templates/basic/_action_form.erb +77 -0
- data/templates/basic/_errors_table.erb +32 -0
- data/templates/basic/_structure_attributes_list.erb +55 -0
- data/templates/basic/action.erb +168 -0
- data/templates/basic/assets/lock.svg +3 -0
- data/templates/basic/assets/reset.css +101 -0
- data/templates/basic/assets/style.css +348 -0
- data/templates/basic/assets/tool.svg +4 -0
- data/templates/basic/assets/try.js +151 -0
- data/templates/basic/authenticator.erb +51 -0
- data/templates/basic/controller.erb +20 -0
- data/templates/basic/index.erb +114 -0
- data/templates/basic/layout.erb +46 -0
- data/templates/basic/structure.erb +23 -0
- data/test/test_helper.rb +81 -0
- data/test/tests/action_access_test.rb +63 -0
- data/test/tests/actions_test.rb +524 -0
- data/test/tests/authenticators_test.rb +87 -0
- data/test/tests/base_test.rb +35 -0
- data/test/tests/controllers_test.rb +49 -0
- data/test/tests/eval_environment_test.rb +136 -0
- data/test/tests/evel_helpers_test.rb +60 -0
- data/test/tests/examples_test.rb +11 -0
- data/test/tests/helpers_test.rb +97 -0
- data/test/tests/param_set_test.rb +44 -0
- data/test/tests/rack_middleware_test.rb +109 -0
- data/test/tests/request_test.rb +232 -0
- data/test/tests/structures_param_extensions_test.rb +159 -0
- data/test/tests/structures_test.rb +335 -0
- metadata +82 -48
data/lib/moonrope/controller.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
require 'moonrope/dsl/controller_dsl'
|
2
|
+
|
1
3
|
module Moonrope
|
2
4
|
class Controller
|
3
5
|
|
4
|
-
attr_accessor :name, :actions, :
|
6
|
+
attr_accessor :name, :actions, :befores, :friendly_name, :description, :doc, :authenticator, :access_rule, :shared_actions
|
5
7
|
attr_reader :base, :dsl
|
6
8
|
|
7
9
|
#
|
@@ -15,7 +17,7 @@ module Moonrope
|
|
15
17
|
@base = base
|
16
18
|
@name = name
|
17
19
|
@actions = {}
|
18
|
-
@
|
20
|
+
@shared_actions = {}
|
19
21
|
@befores = []
|
20
22
|
@dsl = Moonrope::DSL::ControllerDSL.new(self)
|
21
23
|
@dsl.instance_eval(&block) if block_given?
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Moonrope
|
2
|
+
class DocContext
|
3
|
+
|
4
|
+
attr_reader :vars
|
5
|
+
|
6
|
+
def initialize(generator, options = {})
|
7
|
+
@generator = generator
|
8
|
+
@vars = options.delete(:vars) || {}
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def set_page_title(title)
|
13
|
+
@vars[:page_title] = title
|
14
|
+
end
|
15
|
+
|
16
|
+
def set_active_nav(nav)
|
17
|
+
@vars[:active_nav] = nav
|
18
|
+
end
|
19
|
+
|
20
|
+
def base
|
21
|
+
@generator.base
|
22
|
+
end
|
23
|
+
|
24
|
+
def host
|
25
|
+
@generator.host
|
26
|
+
end
|
27
|
+
|
28
|
+
def prefix
|
29
|
+
@generator.prefix
|
30
|
+
end
|
31
|
+
|
32
|
+
def version
|
33
|
+
@generator.version
|
34
|
+
end
|
35
|
+
|
36
|
+
def method_missing(name)
|
37
|
+
if @vars.has_key?(name.to_sym)
|
38
|
+
@vars[name.to_sym]
|
39
|
+
else
|
40
|
+
super
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def git_version
|
45
|
+
ENV["VDT_VERSION"] ||
|
46
|
+
(`git rev-parse HEAD`.strip rescue nil)
|
47
|
+
end
|
48
|
+
|
49
|
+
def asset_path(file)
|
50
|
+
path("assets/" + file)
|
51
|
+
end
|
52
|
+
|
53
|
+
def full_prefix
|
54
|
+
"#{host}/#{prefix}/#{version}"
|
55
|
+
end
|
56
|
+
|
57
|
+
def path(file)
|
58
|
+
depth = ((@options[:output_file] || '').split('/').size - 1).times.map { "../" }.join
|
59
|
+
if file == :root
|
60
|
+
file = depth + (@options[:welcome_file] || "welcome")
|
61
|
+
else
|
62
|
+
file = depth + file
|
63
|
+
end
|
64
|
+
|
65
|
+
if @options[:html_extensions] && !(file =~ /\.[a-z]+\z/)
|
66
|
+
file = "#{file}.html"
|
67
|
+
end
|
68
|
+
|
69
|
+
file
|
70
|
+
end
|
71
|
+
|
72
|
+
def render(template_file)
|
73
|
+
ERB.new(File.read(template_file), nil, '-').result(binding)
|
74
|
+
end
|
75
|
+
|
76
|
+
def partial(name, attributes = {})
|
77
|
+
erb = self.class.new(@generator, @options.merge(:vars => attributes))
|
78
|
+
erb.render(File.join(@generator.template_root_path, "_#{name}.erb"))
|
79
|
+
end
|
80
|
+
|
81
|
+
def friendly_type(type)
|
82
|
+
if type.is_a?(Symbol)
|
83
|
+
type.to_s.capitalize
|
84
|
+
else
|
85
|
+
type.to_s
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def humanize(string)
|
90
|
+
string.to_s.gsub(/\_/, ' ')
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'moonrope/doc_context'
|
2
|
+
|
3
|
+
module Moonrope
|
4
|
+
class DocServer
|
5
|
+
|
6
|
+
CONTENT_TYPES = {
|
7
|
+
'css' => 'text/css',
|
8
|
+
'js' => 'text/javascript',
|
9
|
+
'svg' => 'image/svg+xml'
|
10
|
+
}
|
11
|
+
|
12
|
+
class << self
|
13
|
+
#
|
14
|
+
# Set the default path regex which should be matched for requests for
|
15
|
+
# API docmentation. By default, this is /api/docs/.
|
16
|
+
#
|
17
|
+
def path_regex
|
18
|
+
@path_regex ||= /\A\/#{Moonrope::Request.path_prefix}docs\/([\w\.]+)\/?([\w\/\-\.]+)?/
|
19
|
+
end
|
20
|
+
attr_writer :path_regex
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(app, base, options = {})
|
24
|
+
@app = app
|
25
|
+
@base = base
|
26
|
+
@options = options
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :base
|
30
|
+
|
31
|
+
class Generator
|
32
|
+
def initialize(base, options = {})
|
33
|
+
@base = base
|
34
|
+
@options = options
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_reader :base
|
38
|
+
|
39
|
+
def template_root_path
|
40
|
+
File.expand_path("../../../templates/basic", __FILE__)
|
41
|
+
end
|
42
|
+
|
43
|
+
def host
|
44
|
+
@options[:host]
|
45
|
+
end
|
46
|
+
|
47
|
+
def prefix
|
48
|
+
@options[:prefix]
|
49
|
+
end
|
50
|
+
|
51
|
+
def version
|
52
|
+
@options[:version]
|
53
|
+
end
|
54
|
+
|
55
|
+
def generate_file(output_file, template_file, variables = {})
|
56
|
+
# Generate the page for the requested template with the given variables
|
57
|
+
file = DocContext.new(self, :output_file => output_file, :vars => variables)
|
58
|
+
file_string = file.render(File.join(template_root_path, "#{template_file}.erb"))
|
59
|
+
# Generate the final page within the layout
|
60
|
+
DocContext.new(self, :output_file => output_file, :vars => {:page_title => file.vars[:page_title], :active_nav =>file.vars[:active_nav], :body => file_string}).render(File.join(template_root_path, "layout.erb"))
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def call(env)
|
65
|
+
if env['PATH_INFO'] =~ self.class.path_regex
|
66
|
+
version = $1
|
67
|
+
doc_path = $2
|
68
|
+
request = Rack::Request.new(env)
|
69
|
+
generator = Generator.new(@base, :host => "#{request.scheme}://#{request.host_with_port}", :version => version, :prefix => env['PATH_INFO'].split('/')[1])
|
70
|
+
|
71
|
+
if @options[:reload_on_each_request]
|
72
|
+
@base.load
|
73
|
+
end
|
74
|
+
|
75
|
+
file = nil
|
76
|
+
content_type = nil
|
77
|
+
|
78
|
+
case doc_path
|
79
|
+
when nil, ""
|
80
|
+
return [302, {'Location' => "#{env['PATH_INFO']}/welcome"}, ['']]
|
81
|
+
when /\Awelcome\z/, /\Aindex\.html\z/
|
82
|
+
file = generator.generate_file(doc_path, 'index')
|
83
|
+
when /\Acontrollers\/(\w+)(\.html)?\z/
|
84
|
+
if controller = @base.controller($1.to_sym)
|
85
|
+
file = generator.generate_file(doc_path, 'controller', :controller => controller)
|
86
|
+
end
|
87
|
+
when /\Acontrollers\/(\w+)\/(\w+)(\.html)?\z/
|
88
|
+
if controller = @base.controller($1.to_sym)
|
89
|
+
if action = controller.action($2.to_sym)
|
90
|
+
file = generator.generate_file(doc_path, 'action', :controller => controller, :action => action)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
when /\Astructures\/(\w+)(\.html)?\z/
|
94
|
+
if structure = @base.structure($1.to_sym)
|
95
|
+
file = generator.generate_file(doc_path, 'structure', :structure => structure)
|
96
|
+
end
|
97
|
+
when /\Aauthenticators\/(\w+)(\.html)?\z/
|
98
|
+
if authenticator = @base.authenticators[$1.to_sym]
|
99
|
+
file = generator.generate_file(doc_path, 'authenticator', :authenticator => authenticator)
|
100
|
+
end
|
101
|
+
when /\Aassets\/([\w]+)\.([a-z]+)\z/
|
102
|
+
path = File.join(generator.template_root_path, 'assets', "#{$1}.#{$2}")
|
103
|
+
if File.exist?(path)
|
104
|
+
file = File.read(path)
|
105
|
+
content_type = CONTENT_TYPES[$2] || 'text/plain'
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
if file
|
110
|
+
[200, {
|
111
|
+
'Content-Type' => content_type || 'text/html',
|
112
|
+
'Content-Length' => file.bytesize.to_s},
|
113
|
+
[file]]
|
114
|
+
else
|
115
|
+
[404, {}, ['Not found']]
|
116
|
+
end
|
117
|
+
else
|
118
|
+
return @app.call(env)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
end
|
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'moonrope/errors'
|
2
|
+
require 'moonrope/dsl/filterable_dsl'
|
3
|
+
|
1
4
|
module Moonrope
|
2
5
|
module DSL
|
3
6
|
class ActionDSL
|
@@ -11,6 +14,18 @@ module Moonrope
|
|
11
14
|
@action = action
|
12
15
|
end
|
13
16
|
|
17
|
+
#
|
18
|
+
# Set the title for the action
|
19
|
+
#
|
20
|
+
# title "List all users"
|
21
|
+
#
|
22
|
+
# @param value [String]
|
23
|
+
# @return [void]
|
24
|
+
#
|
25
|
+
def title(value)
|
26
|
+
@action.title = value
|
27
|
+
end
|
28
|
+
|
14
29
|
#
|
15
30
|
# Set the description for the action
|
16
31
|
#
|
@@ -23,6 +38,14 @@ module Moonrope
|
|
23
38
|
@action.description = value
|
24
39
|
end
|
25
40
|
|
41
|
+
|
42
|
+
#
|
43
|
+
# Set this action so that it isn't documented
|
44
|
+
#
|
45
|
+
def no_doc!
|
46
|
+
@action.doc = false
|
47
|
+
end
|
48
|
+
|
26
49
|
#
|
27
50
|
# Add a new param to the action's param set.
|
28
51
|
#
|
@@ -33,27 +56,94 @@ module Moonrope
|
|
33
56
|
# @param options_if_description [Hash] a hash of additional options if a description was provided
|
34
57
|
# @return [void]
|
35
58
|
#
|
36
|
-
def param(name, description_or_options = {}, options_if_description = {})
|
59
|
+
def param(name, description_or_options = {}, options_if_description = {}, &block)
|
37
60
|
if description_or_options.is_a?(String)
|
38
61
|
options = options_if_description.merge(:description => description_or_options)
|
39
62
|
else
|
40
63
|
options = description_or_options
|
41
64
|
end
|
65
|
+
|
66
|
+
options[:from_structure] ||= @from_structure if @from_structure
|
67
|
+
|
68
|
+
if structure = options[:from_structure]
|
69
|
+
if @action.controller && structure = @action.controller.base.structure(structure)
|
70
|
+
if attribute = structure.attribute(name)
|
71
|
+
options[:description] ||= attribute.description
|
72
|
+
options[:type] ||= attribute.value_type
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
options[:apply] = block if block_given?
|
78
|
+
options[:from_shared_action] = @within_shared_action.dup if @within_shared_action
|
42
79
|
@action.params[name] = options
|
43
80
|
end
|
44
81
|
|
45
82
|
#
|
46
|
-
#
|
83
|
+
# Specifies that all params within this block should be marked as being from
|
84
|
+
# a given structure
|
47
85
|
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
86
|
+
# from_structure :user do
|
87
|
+
# param :username
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# @param name [Symbol] the name of the structure
|
51
91
|
#
|
52
|
-
|
92
|
+
def from_structure(name, &block)
|
93
|
+
@from_structure = name
|
94
|
+
self.instance_eval(&block)
|
95
|
+
ensure
|
96
|
+
@from_structure = nil
|
97
|
+
end
|
98
|
+
|
99
|
+
#
|
100
|
+
# Add a new error to the actions' errors
|
101
|
+
#
|
102
|
+
# error "NoUnitFound", "The unit with given {{id}} could not be found"
|
103
|
+
#
|
104
|
+
# @param name [String] the name of the error
|
105
|
+
# @param description [String] a description of the error
|
53
106
|
# @return [void]
|
54
107
|
#
|
55
|
-
def
|
56
|
-
@action.
|
108
|
+
def error(name, description, options = {})
|
109
|
+
@action.errors[name] = options.merge(:description => description, :from_share => @within_share)
|
110
|
+
end
|
111
|
+
|
112
|
+
#
|
113
|
+
# Sets the type of return value that is expected from a successful call
|
114
|
+
# to this API action.
|
115
|
+
#
|
116
|
+
# returns :array, :structure => :user
|
117
|
+
#
|
118
|
+
# @param type [Symbol] the type of object that will be returend
|
119
|
+
# @param options [Hash] further options about the returned value
|
120
|
+
# @return [void]
|
121
|
+
#
|
122
|
+
def returns(type, options = {})
|
123
|
+
@action.returns = options.merge(:type => type)
|
124
|
+
end
|
125
|
+
|
126
|
+
#
|
127
|
+
# Sets the name of the authenticator to use for this action
|
128
|
+
#
|
129
|
+
# @param name [Symbol] the name of the authenticator
|
130
|
+
#
|
131
|
+
def authenticator(name)
|
132
|
+
@action.authenticator = name
|
133
|
+
end
|
134
|
+
|
135
|
+
#
|
136
|
+
# Sets the name of the access rule to use for this action
|
137
|
+
#
|
138
|
+
# @param name [Symbol] the name of the authenticator
|
139
|
+
#
|
140
|
+
def access_rule(name)
|
141
|
+
if name.is_a?(Hash)
|
142
|
+
authenticator name.first[0]
|
143
|
+
access_rule name.first[1]
|
144
|
+
else
|
145
|
+
@action.access_rule = name
|
146
|
+
end
|
57
147
|
end
|
58
148
|
|
59
149
|
#
|
@@ -67,7 +157,67 @@ module Moonrope
|
|
67
157
|
# @return [void]
|
68
158
|
#
|
69
159
|
def action(&block)
|
70
|
-
@action.
|
160
|
+
@action.actions << block
|
161
|
+
end
|
162
|
+
|
163
|
+
#
|
164
|
+
# Specify that this action will be returning paginated data. Sets up the
|
165
|
+
# parameters for the action as appropriate.
|
166
|
+
#
|
167
|
+
def paginated(options = {})
|
168
|
+
@action.traits << :paginated
|
169
|
+
param :page, "The page number", :type => Integer, :required => true, :default => options[:page] || 1
|
170
|
+
param :per_page, "The number of items to return per page", :type => Integer, :required => true, :default => options[:per_page] || 30
|
171
|
+
end
|
172
|
+
|
173
|
+
#
|
174
|
+
# Specify that this action will return data sorted by user provided data.
|
175
|
+
#
|
176
|
+
def sortable(*fields)
|
177
|
+
if fields.empty?
|
178
|
+
raise Moonrope::Errors::Error, "You must specify at least one field when calling 'sortable'"
|
179
|
+
else
|
180
|
+
if fields.first.is_a?(Hash)
|
181
|
+
default_order = fields.first.first[1].to_s
|
182
|
+
fields[0] = fields.first.first[0]
|
183
|
+
else
|
184
|
+
default_order = 'asc'
|
185
|
+
end
|
186
|
+
@action.traits << :sortable
|
187
|
+
param :sort_by, "The field to sort by", :type => String, :required => true, :default => fields[0].to_s, :options => fields.map(&:to_s)
|
188
|
+
param :order, "The direction to order units by", :type => String, :required => true, :default => default_order, :options => ["asc", "desc"]
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
#
|
193
|
+
# Specify that this action will return data which can be filtered by specifying
|
194
|
+
# certain parameters on a filter parameter
|
195
|
+
#
|
196
|
+
def filterable(&block)
|
197
|
+
if @action.errors['FilterError'].nil?
|
198
|
+
error 'FilterError', "An error has occurred while processing filters for this action", :attributes => {:issue_code => "A more specific issue code", :issue_message => "A more specific message about the issue"}
|
199
|
+
end
|
200
|
+
|
201
|
+
if @action.params[:filters].nil?
|
202
|
+
param :filters, "A hash of filters to apply to results", :type => Hash, :default => {}
|
203
|
+
end
|
204
|
+
dsl = FilterableDSL.new(@action)
|
205
|
+
dsl.instance_eval(&block)
|
206
|
+
end
|
207
|
+
|
208
|
+
#
|
209
|
+
# Include any block from the controller shares
|
210
|
+
#
|
211
|
+
def use(name, options = {})
|
212
|
+
if block = (@action.controller.shared_actions[name] || @action.controller.base.shared_actions[name])
|
213
|
+
@within_shared_action ||= []
|
214
|
+
@within_shared_action << name
|
215
|
+
self.instance_exec(options, &block)
|
216
|
+
else
|
217
|
+
raise Moonrope::Errors::InvalidSharedAction, "Invalid share name #{name}"
|
218
|
+
end
|
219
|
+
ensure
|
220
|
+
@within_shared_action.delete(name) if @within_shared_action
|
71
221
|
end
|
72
222
|
|
73
223
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Moonrope
|
2
|
+
module DSL
|
3
|
+
class AuthenticatorDSL
|
4
|
+
|
5
|
+
def initialize(authenticator)
|
6
|
+
@authenticator = authenticator
|
7
|
+
end
|
8
|
+
|
9
|
+
def description(value)
|
10
|
+
@authenticator.description = value
|
11
|
+
end
|
12
|
+
|
13
|
+
def header(name, description = nil, options = {})
|
14
|
+
@authenticator.headers[name] = options.merge(:name => name, :description => description)
|
15
|
+
end
|
16
|
+
|
17
|
+
def error(name, description = nil, options = {})
|
18
|
+
@authenticator.errors[name] = options.merge(:name => name, :description => description)
|
19
|
+
end
|
20
|
+
|
21
|
+
def lookup(&block)
|
22
|
+
@authenticator.lookup = block
|
23
|
+
end
|
24
|
+
|
25
|
+
def rule(name, error_code, description = nil, &block)
|
26
|
+
@authenticator.rules[name] = {:name => name, :error_code => error_code, :description => description, :block => block}
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -1,3 +1,7 @@
|
|
1
|
+
require 'moonrope/structure'
|
2
|
+
require 'moonrope/controller'
|
3
|
+
require 'moonrope/authenticator'
|
4
|
+
|
1
5
|
module Moonrope
|
2
6
|
module DSL
|
3
7
|
class BaseDSL
|
@@ -47,24 +51,6 @@ module Moonrope
|
|
47
51
|
controller
|
48
52
|
end
|
49
53
|
|
50
|
-
#
|
51
|
-
# Set the authenticator for the API.
|
52
|
-
#
|
53
|
-
# @yield stores the block as the authenticator
|
54
|
-
#
|
55
|
-
def authenticator(&block)
|
56
|
-
@base.authenticator = block
|
57
|
-
end
|
58
|
-
|
59
|
-
#
|
60
|
-
# Set the default access check block.
|
61
|
-
#
|
62
|
-
# @yield stores the block as the access check
|
63
|
-
#
|
64
|
-
def default_access(value = nil, &block)
|
65
|
-
@base.default_access = block_given? ? block : value
|
66
|
-
end
|
67
|
-
|
68
54
|
#
|
69
55
|
# Define a new helper in the global namespace
|
70
56
|
#
|
@@ -81,6 +67,23 @@ module Moonrope
|
|
81
67
|
helper_instance
|
82
68
|
end
|
83
69
|
|
70
|
+
#
|
71
|
+
# Define a new authenticator
|
72
|
+
#
|
73
|
+
def authenticator(name, &block)
|
74
|
+
authenticator = Moonrope::Authenticator.new(name)
|
75
|
+
dsl = Moonrope::DSL::AuthenticatorDSL.new(authenticator)
|
76
|
+
dsl.instance_eval(&block) if block_given?
|
77
|
+
@base.authenticators[name] = authenticator
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
# Define a new global shared action
|
82
|
+
#
|
83
|
+
def shared_action(name, &block)
|
84
|
+
@base.shared_actions[name] = block
|
85
|
+
end
|
86
|
+
|
84
87
|
end
|
85
88
|
end
|
86
89
|
end
|
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'moonrope/action'
|
2
|
+
require 'moonrope/before_action'
|
3
|
+
|
1
4
|
module Moonrope
|
2
5
|
module DSL
|
3
6
|
class ControllerDSL
|
@@ -14,6 +17,31 @@ module Moonrope
|
|
14
17
|
# @return [Moonrope::Controller] the associated controller
|
15
18
|
attr_reader :controller
|
16
19
|
|
20
|
+
#
|
21
|
+
# Stop this controller frmo being documented
|
22
|
+
#
|
23
|
+
def no_doc!
|
24
|
+
@controller.doc = false
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
# Set the friendly name for the controller
|
29
|
+
#
|
30
|
+
# @param name [String]
|
31
|
+
#
|
32
|
+
def friendly_name(string)
|
33
|
+
@controller.friendly_name = string
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Set the description for the controller
|
38
|
+
#
|
39
|
+
# @param description [String]
|
40
|
+
#
|
41
|
+
def description(description)
|
42
|
+
@controller.description = description
|
43
|
+
end
|
44
|
+
|
17
45
|
#
|
18
46
|
# Defines a new action within the controller.
|
19
47
|
#
|
@@ -28,6 +56,29 @@ module Moonrope
|
|
28
56
|
action
|
29
57
|
end
|
30
58
|
|
59
|
+
#
|
60
|
+
# Set the name of the authenticator to use for all actions in this controller
|
61
|
+
#
|
62
|
+
# @param name [Symbol]
|
63
|
+
#
|
64
|
+
def authenticator(name)
|
65
|
+
@controller.authenticator = name
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# Set the name of the access rule to use for all actions in this controller
|
70
|
+
#
|
71
|
+
# @param name [Symbol]
|
72
|
+
#
|
73
|
+
def access_rule(name)
|
74
|
+
if name.is_a?(Hash)
|
75
|
+
authenticator name.first[0]
|
76
|
+
access_rule name.first[1]
|
77
|
+
else
|
78
|
+
@controller.access_rule = name
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
31
82
|
#
|
32
83
|
# Defines a new before action within the controller.
|
33
84
|
#
|
@@ -43,14 +94,6 @@ module Moonrope
|
|
43
94
|
before_action
|
44
95
|
end
|
45
96
|
|
46
|
-
#
|
47
|
-
# Defines the access required for controller methods which do not
|
48
|
-
# define their own access.
|
49
|
-
#
|
50
|
-
def access(value = nil, &block)
|
51
|
-
@controller.access = block_given? ? block : value
|
52
|
-
end
|
53
|
-
|
54
97
|
#
|
55
98
|
# Defines a new helper for this controller.
|
56
99
|
#
|
@@ -61,9 +104,17 @@ module Moonrope
|
|
61
104
|
if @controller.base.helper(name, @controller)
|
62
105
|
raise Moonrope::Errors::HelperAlreadyDefined, "Helper has already been defined with name `#{name}`"
|
63
106
|
end
|
64
|
-
|
65
107
|
@controller.base.helpers << Moonrope::Helper.new(name, @controller, options, &block)
|
66
108
|
end
|
109
|
+
|
110
|
+
#
|
111
|
+
# Define a shared action which can be used by any action
|
112
|
+
#
|
113
|
+
# @param name[Symbol] the name of the shared action
|
114
|
+
#
|
115
|
+
def shared_action(name, &block)
|
116
|
+
@controller.shared_actions[name] = block
|
117
|
+
end
|
67
118
|
end
|
68
119
|
end
|
69
120
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Moonrope
|
2
|
+
module DSL
|
3
|
+
class FilterableDSL
|
4
|
+
|
5
|
+
def initialize(action)
|
6
|
+
@action = action
|
7
|
+
end
|
8
|
+
|
9
|
+
def attribute(name, options = {}, &block)
|
10
|
+
if options[:type] == Integer || options[:type] == Float
|
11
|
+
# Numbers
|
12
|
+
options[:operators] ||= [:eq, :not_eq, :gt, :gte, :lt, :lte, :in, :not_in]
|
13
|
+
elsif options[:type] == String
|
14
|
+
# Strings
|
15
|
+
options[:operators] ||= [:eq, :not_eq, :starts_with, :ends_with, :in, :not_in]
|
16
|
+
elsif options[:type] == :timestamp
|
17
|
+
# Times
|
18
|
+
options[:operators] ||= [:eq, :not_eq, :gt, :gte, :lt, :lte]
|
19
|
+
else
|
20
|
+
# Everything else
|
21
|
+
options[:operators] ||= [:eq, :not_eq]
|
22
|
+
end
|
23
|
+
@action.filters[name] = options.merge(:name => name, :block => block)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|