moon 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/README.rdoc +2 -0
  2. data/Rakefile +10 -3
  3. data/lib/moon.rb +0 -2
  4. data/lib/moon/action.rb +4 -3
  5. data/lib/moon/action/inject_timestamps.rb +44 -0
  6. data/lib/moon/action/model.rb +1 -2
  7. data/lib/moon/action/model/destroy.rb +4 -26
  8. data/lib/moon/action/model/index.rb +10 -17
  9. data/lib/moon/action/model/show.rb +9 -23
  10. data/lib/moon/action/model/store.rb +20 -0
  11. data/lib/moon/action/models/finder.rb +14 -14
  12. data/lib/moon/action/models/initializer.rb +6 -5
  13. data/lib/moon/action/models/updater.rb +1 -4
  14. data/lib/moon/action/rebuild_arrays.rb +1 -4
  15. data/lib/moon/action/{reference_object.rb → reference.rb} +1 -1
  16. data/lib/moon/action/respond_blank.rb +9 -0
  17. data/lib/moon/action/transfer.rb +30 -0
  18. data/lib/moon/action/valid_models_required.rb +13 -6
  19. data/lib/moon/application.rb +12 -7
  20. data/lib/moon/application/configuration.rb +55 -0
  21. data/lib/moon/application/rack.rb +17 -7
  22. data/lib/moon/context.rb +1 -1
  23. data/lib/moon/formatter.rb +4 -13
  24. data/lib/moon/formatter/generic.rb +17 -4
  25. data/lib/moon/response/json.rb +1 -0
  26. data/lib/moon/response/json/blank.rb +9 -0
  27. data/lib/moon/response/json/collection.rb +2 -2
  28. data/lib/moon/response/json/model.rb +3 -3
  29. data/lib/moon/validator.rb +17 -45
  30. data/lib/moon/validator/format.rb +4 -23
  31. data/lib/moon/validator/length.rb +8 -33
  32. data/lib/moon/validator/presence.rb +4 -17
  33. data/spec/lib/moon/action/inject_timestamps_spec.rb +46 -0
  34. data/spec/lib/moon/action/model/destroy_spec.rb +6 -44
  35. data/spec/lib/moon/action/model/index_spec.rb +8 -25
  36. data/spec/lib/moon/action/model/show_spec.rb +33 -25
  37. data/spec/lib/moon/action/model/store_spec.rb +77 -0
  38. data/spec/lib/moon/action/models/finder_spec.rb +25 -11
  39. data/spec/lib/moon/action/models/initializer_spec.rb +7 -5
  40. data/spec/lib/moon/action/models/updater_spec.rb +5 -3
  41. data/spec/lib/moon/action/rebuild_arrays_spec.rb +3 -3
  42. data/spec/lib/moon/action/{reference_object_spec.rb → reference_spec.rb} +1 -1
  43. data/spec/lib/moon/action/respond_blank_spec.rb +24 -0
  44. data/spec/lib/moon/action/transfer_spec.rb +30 -0
  45. data/spec/lib/moon/action/valid_models_required_spec.rb +19 -17
  46. data/spec/lib/moon/application/configuration_spec.rb +75 -0
  47. data/spec/lib/moon/application/rack_spec.rb +6 -5
  48. data/spec/lib/moon/formatter/generic_spec.rb +13 -3
  49. data/spec/lib/moon/formatter_spec.rb +4 -10
  50. data/spec/lib/moon/response/json/blank_spec.rb +19 -0
  51. data/spec/lib/moon/response/json/collection_spec.rb +5 -4
  52. data/spec/lib/moon/response/json/model_spec.rb +5 -4
  53. data/spec/lib/moon/validator/format_spec.rb +8 -25
  54. data/spec/lib/moon/validator/length_spec.rb +10 -36
  55. data/spec/lib/moon/validator/presence_spec.rb +11 -28
  56. data/spec/lib/moon/validator_spec.rb +10 -59
  57. metadata +34 -28
  58. data/lib/moon/action/base.rb +0 -16
  59. data/lib/moon/action/model/create.rb +0 -45
  60. data/lib/moon/action/model/update.rb +0 -42
  61. data/lib/moon/application/routes.rb +0 -16
  62. data/lib/moon/formatter/base.rb +0 -15
  63. data/spec/lib/moon/action/base_spec.rb +0 -29
  64. data/spec/lib/moon/action/model/create_spec.rb +0 -111
  65. data/spec/lib/moon/action/model/update_spec.rb +0 -91
  66. data/spec/lib/moon/application/routes_spec.rb +0 -26
  67. data/spec/lib/moon/formatter/base_spec.rb +0 -30
@@ -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 :routes
15
- attr_reader :rack
14
+ attr_reader :configuration
16
15
 
17
16
  def initialize
18
- @routes = Routes.new
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
- @routes.rack.transponder
27
+ @rack.transponder
23
28
  end
24
29
 
25
30
  def environment
26
31
  @rack.environment
27
32
  end
28
33
 
29
- def self.storage_name(environment)
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.storage_name = Moon::Application.storage_name @environment
95
+ @context.application = @application
86
96
  end
87
97
 
88
98
  def perform_actions
@@ -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 :storage_name
5
+ attr_accessor :application
6
6
 
7
7
  def initialize(session = { }, parameters = { })
8
8
  @session, @parameters = session, parameters
@@ -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.configuration=(value)
9
- @configuration = value
10
- end
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 < Moon::Formatter::Base
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
- @hash[key] = @model.instance_variable_get variable_name
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
- @hash[:id] = GOM::Object.id @model
38
+ id = GOM::Object.id @model
39
+ @hash[:id] = id if id
27
40
  end
28
41
 
29
42
  end
@@ -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")
@@ -0,0 +1,9 @@
1
+
2
+ # Moon::Response::JSON::Blank provides a simple response with an empty hash
3
+ class Moon::Response::JSON::Blank < Moon::Response::JSON
4
+
5
+ def initialize
6
+ super 200, { }
7
+ end
8
+
9
+ end
@@ -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
@@ -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 :model
9
+ attr_reader :model_class
10
10
 
11
- def initialize(model)
12
- @model = model
11
+ def initialize(context, checks)
12
+ @context, @checks = context, checks
13
13
  end
14
14
 
15
- def ok?
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
- @ok, @messages = true, { }
29
- self.class.checks.each do |attribute, attribute_validator_class|
30
- perform_attribute_checks attribute, attribute_validator_class
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, attribute_validator_classes)
35
- attribute_validator_classes.each do |attribute_validator_class|
36
- attribute_validator = attribute_validator_class.new @model.send(attribute)
37
- ok, message = attribute_validator.ok?, attribute_validator.message
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 add_message(attribute, ok, message)
44
- return if ok || !message
37
+ def add_messages(attribute, messages)
38
+ return if messages.empty?
45
39
  @messages[attribute] ||= [ ]
46
- @messages[attribute] << message
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
- template :format
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 message
21
- check
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
- template :minimum, :maximum
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 minimum
26
- self.class.minimum
27
- end
28
-
29
- def maximum
30
- self.class.maximum
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