moon 0.0.1 → 0.0.2
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.
- 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
|