moon 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +2 -0
- data/Rakefile +10 -3
- data/lib/moon.rb +0 -2
- data/lib/moon/action.rb +4 -3
- data/lib/moon/action/inject_timestamps.rb +44 -0
- data/lib/moon/action/model.rb +1 -2
- data/lib/moon/action/model/destroy.rb +4 -26
- data/lib/moon/action/model/index.rb +10 -17
- data/lib/moon/action/model/show.rb +9 -23
- data/lib/moon/action/model/store.rb +20 -0
- data/lib/moon/action/models/finder.rb +14 -14
- data/lib/moon/action/models/initializer.rb +6 -5
- data/lib/moon/action/models/updater.rb +1 -4
- data/lib/moon/action/rebuild_arrays.rb +1 -4
- data/lib/moon/action/{reference_object.rb → reference.rb} +1 -1
- data/lib/moon/action/respond_blank.rb +9 -0
- data/lib/moon/action/transfer.rb +30 -0
- data/lib/moon/action/valid_models_required.rb +13 -6
- data/lib/moon/application.rb +12 -7
- data/lib/moon/application/configuration.rb +55 -0
- data/lib/moon/application/rack.rb +17 -7
- data/lib/moon/context.rb +1 -1
- data/lib/moon/formatter.rb +4 -13
- data/lib/moon/formatter/generic.rb +17 -4
- data/lib/moon/response/json.rb +1 -0
- data/lib/moon/response/json/blank.rb +9 -0
- data/lib/moon/response/json/collection.rb +2 -2
- data/lib/moon/response/json/model.rb +3 -3
- data/lib/moon/validator.rb +17 -45
- data/lib/moon/validator/format.rb +4 -23
- data/lib/moon/validator/length.rb +8 -33
- data/lib/moon/validator/presence.rb +4 -17
- data/spec/lib/moon/action/inject_timestamps_spec.rb +46 -0
- data/spec/lib/moon/action/model/destroy_spec.rb +6 -44
- data/spec/lib/moon/action/model/index_spec.rb +8 -25
- data/spec/lib/moon/action/model/show_spec.rb +33 -25
- data/spec/lib/moon/action/model/store_spec.rb +77 -0
- data/spec/lib/moon/action/models/finder_spec.rb +25 -11
- data/spec/lib/moon/action/models/initializer_spec.rb +7 -5
- data/spec/lib/moon/action/models/updater_spec.rb +5 -3
- data/spec/lib/moon/action/rebuild_arrays_spec.rb +3 -3
- data/spec/lib/moon/action/{reference_object_spec.rb → reference_spec.rb} +1 -1
- data/spec/lib/moon/action/respond_blank_spec.rb +24 -0
- data/spec/lib/moon/action/transfer_spec.rb +30 -0
- data/spec/lib/moon/action/valid_models_required_spec.rb +19 -17
- data/spec/lib/moon/application/configuration_spec.rb +75 -0
- data/spec/lib/moon/application/rack_spec.rb +6 -5
- data/spec/lib/moon/formatter/generic_spec.rb +13 -3
- data/spec/lib/moon/formatter_spec.rb +4 -10
- data/spec/lib/moon/response/json/blank_spec.rb +19 -0
- data/spec/lib/moon/response/json/collection_spec.rb +5 -4
- data/spec/lib/moon/response/json/model_spec.rb +5 -4
- data/spec/lib/moon/validator/format_spec.rb +8 -25
- data/spec/lib/moon/validator/length_spec.rb +10 -36
- data/spec/lib/moon/validator/presence_spec.rb +11 -28
- data/spec/lib/moon/validator_spec.rb +10 -59
- metadata +34 -28
- data/lib/moon/action/base.rb +0 -16
- data/lib/moon/action/model/create.rb +0 -45
- data/lib/moon/action/model/update.rb +0 -42
- data/lib/moon/application/routes.rb +0 -16
- data/lib/moon/formatter/base.rb +0 -15
- data/spec/lib/moon/action/base_spec.rb +0 -29
- data/spec/lib/moon/action/model/create_spec.rb +0 -111
- data/spec/lib/moon/action/model/update_spec.rb +0 -91
- data/spec/lib/moon/application/routes_spec.rb +0 -26
- data/spec/lib/moon/formatter/base_spec.rb +0 -30
data/lib/moon/application.rb
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
# Main application class.
|
3
3
|
class Moon::Application
|
4
4
|
|
5
|
+
autoload :Configuration, File.join(File.dirname(__FILE__), "application", "configuration")
|
5
6
|
autoload :Rack, File.join(File.dirname(__FILE__), "application", "rack")
|
6
|
-
autoload :Routes, File.join(File.dirname(__FILE__), "application", "routes")
|
7
7
|
|
8
8
|
# This error is raised if an action doesn't respond to :perform.
|
9
9
|
class InvalidActionError < StandardError; end
|
@@ -11,23 +11,28 @@ class Moon::Application
|
|
11
11
|
# This error is raised if a response doesn't respond to :status, :headers and :body.
|
12
12
|
class InvalidResponseError < StandardError; end
|
13
13
|
|
14
|
-
attr_reader :
|
15
|
-
attr_reader :rack
|
14
|
+
attr_reader :configuration
|
16
15
|
|
17
16
|
def initialize
|
18
|
-
@
|
17
|
+
@rack = Rack.new self
|
18
|
+
end
|
19
|
+
|
20
|
+
def configure(&block)
|
21
|
+
@configuration = Configuration.new &block
|
22
|
+
@rack.session = @configuration.session
|
23
|
+
@rack.routes = @configuration.routes
|
19
24
|
end
|
20
25
|
|
21
26
|
def rack
|
22
|
-
@
|
27
|
+
@rack.transponder
|
23
28
|
end
|
24
29
|
|
25
30
|
def environment
|
26
31
|
@rack.environment
|
27
32
|
end
|
28
33
|
|
29
|
-
def
|
30
|
-
environment == :test ? :dump : :main
|
34
|
+
def storage_name
|
35
|
+
@rack.environment == :test ? :dump : :main
|
31
36
|
end
|
32
37
|
|
33
38
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'configure'
|
2
|
+
|
3
|
+
# Application configuration.
|
4
|
+
class Moon::Application::Configuration
|
5
|
+
|
6
|
+
SCHEMA = Configure::Schema.build {
|
7
|
+
only :session, :route, :validator, :formatter
|
8
|
+
nested {
|
9
|
+
session {
|
10
|
+
only :secret
|
11
|
+
}
|
12
|
+
route {
|
13
|
+
only :http_method, :path, :actions
|
14
|
+
argument_keys :http_method, :path
|
15
|
+
}
|
16
|
+
validator {
|
17
|
+
only :model_class, :attributes
|
18
|
+
}
|
19
|
+
formatter {
|
20
|
+
only :model_class, :object
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}.freeze
|
24
|
+
|
25
|
+
def initialize(&block)
|
26
|
+
@hash = Configure.process SCHEMA, &block
|
27
|
+
end
|
28
|
+
|
29
|
+
def session
|
30
|
+
@hash[:session]
|
31
|
+
end
|
32
|
+
|
33
|
+
def routes
|
34
|
+
[ @hash[:route] ].compact.flatten
|
35
|
+
end
|
36
|
+
|
37
|
+
def validators
|
38
|
+
validators = { }
|
39
|
+
[ @hash[:validator] ].compact.flatten.each do |validator_hash|
|
40
|
+
model_class, attributes = validator_hash.values_at :model_class, :attributes
|
41
|
+
validators[model_class] = attributes
|
42
|
+
end
|
43
|
+
validators
|
44
|
+
end
|
45
|
+
|
46
|
+
def formatters
|
47
|
+
formatters = { }
|
48
|
+
[ @hash[:formatter] ].compact.flatten.each do |formatter_hash|
|
49
|
+
model_class, object = formatter_hash.values_at :model_class, :object
|
50
|
+
formatters[model_class] = object
|
51
|
+
end
|
52
|
+
formatters
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -7,10 +7,16 @@ class Moon::Application::Rack
|
|
7
7
|
attr_reader :transponder
|
8
8
|
attr_reader :environment
|
9
9
|
|
10
|
-
def initialize
|
10
|
+
def initialize(application)
|
11
|
+
@application = application
|
11
12
|
initialize_transponder
|
12
13
|
end
|
13
14
|
|
15
|
+
def session=(session)
|
16
|
+
@session = session
|
17
|
+
set_session_secret
|
18
|
+
end
|
19
|
+
|
14
20
|
def routes=(routes)
|
15
21
|
@routes = routes
|
16
22
|
map_routes
|
@@ -36,20 +42,23 @@ class Moon::Application::Rack
|
|
36
42
|
|
37
43
|
def map_routes
|
38
44
|
@routes.each do |route|
|
39
|
-
Route.new(@transponder, route).define
|
45
|
+
Route.new(@application, @transponder, route).define
|
40
46
|
end
|
41
47
|
end
|
42
48
|
|
49
|
+
def set_session_secret
|
50
|
+
@transponder.set :session_secret, @session[:secret]
|
51
|
+
end
|
52
|
+
|
43
53
|
# Abstraction for a application route
|
44
54
|
class Route
|
45
55
|
|
46
56
|
attr_reader :response
|
47
57
|
attr_reader :rack_response
|
48
58
|
|
49
|
-
def initialize(transponder, route)
|
50
|
-
@transponder = transponder
|
59
|
+
def initialize(application, transponder, route)
|
60
|
+
@application, @transponder, @route = application, transponder, route
|
51
61
|
@environment = @transponder.environment
|
52
|
-
@route = route
|
53
62
|
end
|
54
63
|
|
55
64
|
def http_method
|
@@ -61,7 +70,8 @@ class Moon::Application::Rack
|
|
61
70
|
end
|
62
71
|
|
63
72
|
def actions
|
64
|
-
@route[:actions]
|
73
|
+
actions = @route[:actions]
|
74
|
+
actions.is_a?(Array) ? actions : [ actions ].compact
|
65
75
|
end
|
66
76
|
|
67
77
|
def define
|
@@ -82,7 +92,7 @@ class Moon::Application::Rack
|
|
82
92
|
|
83
93
|
def build_context(session, params)
|
84
94
|
@context = Moon::Context.new session, params
|
85
|
-
@context.
|
95
|
+
@context.application = @application
|
86
96
|
end
|
87
97
|
|
88
98
|
def perform_actions
|
data/lib/moon/context.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# Context class that contains anything necessary to run a guard, action or response builder.
|
3
3
|
class Moon::Context
|
4
4
|
|
5
|
-
attr_accessor :
|
5
|
+
attr_accessor :application
|
6
6
|
|
7
7
|
def initialize(session = { }, parameters = { })
|
8
8
|
@session, @parameters = session, parameters
|
data/lib/moon/formatter.rb
CHANGED
@@ -2,21 +2,12 @@
|
|
2
2
|
# Model formatter
|
3
3
|
class Moon::Formatter
|
4
4
|
|
5
|
-
autoload :Base, File.join(File.dirname(__FILE__), "formatter", "base")
|
6
5
|
autoload :Generic, File.join(File.dirname(__FILE__), "formatter", "generic")
|
7
6
|
|
8
|
-
def self.
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
def self.configuration
|
13
|
-
@configuration
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.hash_for(model)
|
17
|
-
formatter_class = (@configuration || { })[model.class]
|
18
|
-
formatter_class ||= Moon::Formatter::Generic
|
19
|
-
formatter_class.new(model).hash
|
7
|
+
def self.hash_for(formatters, model)
|
8
|
+
formatter = formatters[model.class]
|
9
|
+
formatter ||= Moon::Formatter::Generic.new
|
10
|
+
formatter.hash model
|
20
11
|
end
|
21
12
|
|
22
13
|
end
|
@@ -1,8 +1,9 @@
|
|
1
1
|
|
2
2
|
# Outputs a hash with all instance variables of the given model.
|
3
|
-
class Moon::Formatter::Generic
|
3
|
+
class Moon::Formatter::Generic
|
4
4
|
|
5
|
-
def hash
|
5
|
+
def hash(model)
|
6
|
+
@model = model
|
6
7
|
initialize_hash
|
7
8
|
inject_instance_variables
|
8
9
|
inject_id
|
@@ -18,12 +19,24 @@ class Moon::Formatter::Generic < Moon::Formatter::Base
|
|
18
19
|
def inject_instance_variables
|
19
20
|
@model.instance_variables.each do |variable_name|
|
20
21
|
key = variable_name.to_s.sub(/^@/, "").to_sym
|
21
|
-
|
22
|
+
value = @model.instance_variable_get variable_name
|
23
|
+
value.is_a?(GOM::Object::Proxy) ?
|
24
|
+
put_reference(key, value) :
|
25
|
+
put_regular(key, value)
|
22
26
|
end
|
23
27
|
end
|
24
28
|
|
29
|
+
def put_regular(key, value)
|
30
|
+
@hash[key] = value
|
31
|
+
end
|
32
|
+
|
33
|
+
def put_reference(key, reference)
|
34
|
+
@hash[:"#{key}_id"] = reference.id
|
35
|
+
end
|
36
|
+
|
25
37
|
def inject_id
|
26
|
-
|
38
|
+
id = GOM::Object.id @model
|
39
|
+
@hash[:id] = id if id
|
27
40
|
end
|
28
41
|
|
29
42
|
end
|
data/lib/moon/response/json.rb
CHANGED
@@ -3,6 +3,7 @@ require 'json'
|
|
3
3
|
# Moon::Response::JSON is the base class for all json responses.
|
4
4
|
class Moon::Response::JSON < Moon::Response::Base
|
5
5
|
|
6
|
+
autoload :Blank, File.join(File.dirname(__FILE__), "json", "blank")
|
6
7
|
autoload :Collection, File.join(File.dirname(__FILE__), "json", "collection")
|
7
8
|
autoload :Message, File.join(File.dirname(__FILE__), "json", "message")
|
8
9
|
autoload :Model, File.join(File.dirname(__FILE__), "json", "model")
|
@@ -2,9 +2,9 @@
|
|
2
2
|
# Moon::Response::JSON::Collection provides a response that contains one single collection.
|
3
3
|
class Moon::Response::JSON::Collection < Moon::Response::JSON
|
4
4
|
|
5
|
-
def initialize(collection)
|
5
|
+
def initialize(collection, formatters)
|
6
6
|
@collection = collection.map do |object|
|
7
|
-
Moon::Formatter.hash_for object
|
7
|
+
Moon::Formatter.hash_for formatters, object
|
8
8
|
end
|
9
9
|
super 200, @collection
|
10
10
|
end
|
@@ -2,15 +2,15 @@
|
|
2
2
|
# Moon::Response::JSON::Collection provides a response that contains one single collection.
|
3
3
|
class Moon::Response::JSON::Model < Moon::Response::JSON
|
4
4
|
|
5
|
-
def initialize(key, object)
|
6
|
-
@key, @object = key, object
|
5
|
+
def initialize(key, object, formatters)
|
6
|
+
@key, @object, @formatters = key, object, formatters
|
7
7
|
super 200, hash
|
8
8
|
end
|
9
9
|
|
10
10
|
private
|
11
11
|
|
12
12
|
def hash
|
13
|
-
{ @key.to_s => Moon::Formatter.hash_for(@object) }
|
13
|
+
{ @key.to_s => Moon::Formatter.hash_for(@formatters, @object) }
|
14
14
|
end
|
15
15
|
|
16
16
|
end
|
data/lib/moon/validator.rb
CHANGED
@@ -6,66 +6,38 @@ class Moon::Validator
|
|
6
6
|
autoload :Length, File.join(File.dirname(__FILE__), "validator", "length")
|
7
7
|
autoload :Presence, File.join(File.dirname(__FILE__), "validator", "presence")
|
8
8
|
|
9
|
-
attr_reader :
|
9
|
+
attr_reader :model_class
|
10
10
|
|
11
|
-
def initialize(
|
12
|
-
@
|
11
|
+
def initialize(context, checks)
|
12
|
+
@context, @checks = context, checks
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
16
|
-
perform_checks
|
17
|
-
@ok
|
18
|
-
end
|
19
|
-
|
20
|
-
def messages
|
21
|
-
perform_checks
|
15
|
+
def messages(model)
|
16
|
+
perform_checks model
|
22
17
|
@messages
|
23
18
|
end
|
24
19
|
|
25
20
|
private
|
26
21
|
|
27
|
-
def perform_checks
|
28
|
-
@
|
29
|
-
|
30
|
-
|
22
|
+
def perform_checks(model)
|
23
|
+
@messages = { }
|
24
|
+
@checks.each do |attribute, attribute_validator|
|
25
|
+
value = model.send attribute
|
26
|
+
perform_attribute_checks attribute, value, [ attribute_validator ].compact.flatten
|
31
27
|
end
|
32
28
|
end
|
33
29
|
|
34
|
-
def perform_attribute_checks(attribute,
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
@ok &&= ok
|
39
|
-
add_message attribute, ok, message
|
30
|
+
def perform_attribute_checks(attribute, value, attribute_validators)
|
31
|
+
attribute_validators.each do |attribute_validator|
|
32
|
+
messages = attribute_validator.messages value, @context
|
33
|
+
add_messages attribute, messages
|
40
34
|
end
|
41
35
|
end
|
42
36
|
|
43
|
-
def
|
44
|
-
return if
|
37
|
+
def add_messages(attribute, messages)
|
38
|
+
return if messages.empty?
|
45
39
|
@messages[attribute] ||= [ ]
|
46
|
-
@messages[attribute]
|
47
|
-
end
|
48
|
-
|
49
|
-
def self.configuration=(value)
|
50
|
-
@configuration = value
|
51
|
-
end
|
52
|
-
|
53
|
-
def self.configuration
|
54
|
-
@configuration
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.checks=(value)
|
58
|
-
@checks = value
|
59
|
-
end
|
60
|
-
|
61
|
-
def self.checks
|
62
|
-
@checks || { }
|
63
|
-
end
|
64
|
-
|
65
|
-
def self.[](model_class)
|
66
|
-
validator = self.dup
|
67
|
-
validator.checks = self.configuration[model_class]
|
68
|
-
validator
|
40
|
+
@messages[attribute] += messages
|
69
41
|
end
|
70
42
|
|
71
43
|
end
|
@@ -1,32 +1,13 @@
|
|
1
1
|
|
2
2
|
# Value format validator.
|
3
3
|
class Moon::Validator::Format
|
4
|
-
extend Moon::Utility::Template
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
attr_accessor :value
|
9
|
-
|
10
|
-
def initialize(value)
|
11
|
-
@value = value
|
12
|
-
@ok, @message = true, nil
|
13
|
-
end
|
14
|
-
|
15
|
-
def ok?
|
16
|
-
check
|
17
|
-
@ok
|
5
|
+
def initialize(format)
|
6
|
+
@format = format
|
18
7
|
end
|
19
8
|
|
20
|
-
def
|
21
|
-
|
22
|
-
@message
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def check
|
28
|
-
@ok = @value =~ self.class.format
|
29
|
-
@message = "Has a wrong format." unless @ok
|
9
|
+
def messages(value, context)
|
10
|
+
value =~ @format ? [ ] : [ "Has a wrong format." ]
|
30
11
|
end
|
31
12
|
|
32
13
|
end
|
@@ -1,42 +1,17 @@
|
|
1
1
|
|
2
2
|
# Value length validator.
|
3
3
|
class Moon::Validator::Length
|
4
|
-
extend Moon::Utility::Template
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
attr_accessor :value
|
9
|
-
|
10
|
-
def initialize(value)
|
11
|
-
@value = value
|
12
|
-
@ok, @messages = true, [ ]
|
13
|
-
end
|
14
|
-
|
15
|
-
def ok?
|
16
|
-
check
|
17
|
-
@ok
|
18
|
-
end
|
19
|
-
|
20
|
-
def message
|
21
|
-
check
|
22
|
-
@message
|
5
|
+
def initialize(range)
|
6
|
+
@range = range
|
23
7
|
end
|
24
8
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def check
|
36
|
-
raise ArgumentError, "Value doesn't response to :size" unless @value.respond_to?(:size)
|
37
|
-
size, minimum, maximum = @value.size, self.minimum, self.maximum
|
38
|
-
@ok = (!minimum || size >= minimum) && (!maximum || size <= maximum)
|
39
|
-
@message = "Must have at #{size < minimum ? ("least " + minimum.to_s) : ("most " + maximum.to_s)} entries." unless @ok
|
9
|
+
def messages(value, context)
|
10
|
+
raise ArgumentError, "Value doesn't response to :size" unless value.respond_to?(:size)
|
11
|
+
size, minimum, maximum = value.size, @range.min, @range.max
|
12
|
+
@range.include?(size) ?
|
13
|
+
[ ] :
|
14
|
+
[ "Must have at #{size < minimum ? ("least " + minimum.to_s) : ("most " + maximum.to_s)} entries." ]
|
40
15
|
end
|
41
16
|
|
42
17
|
end
|