moon 0.0.1

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.
Files changed (72) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +11 -0
  3. data/Rakefile +48 -0
  4. data/lib/moon.rb +15 -0
  5. data/lib/moon/action.rb +12 -0
  6. data/lib/moon/action/base.rb +16 -0
  7. data/lib/moon/action/model.rb +10 -0
  8. data/lib/moon/action/model/create.rb +45 -0
  9. data/lib/moon/action/model/destroy.rb +42 -0
  10. data/lib/moon/action/model/index.rb +31 -0
  11. data/lib/moon/action/model/show.rb +32 -0
  12. data/lib/moon/action/model/update.rb +42 -0
  13. data/lib/moon/action/models.rb +8 -0
  14. data/lib/moon/action/models/finder.rb +43 -0
  15. data/lib/moon/action/models/initializer.rb +51 -0
  16. data/lib/moon/action/models/updater.rb +36 -0
  17. data/lib/moon/action/rebuild_arrays.rb +40 -0
  18. data/lib/moon/action/reference_object.rb +35 -0
  19. data/lib/moon/action/valid_models_required.rb +21 -0
  20. data/lib/moon/application.rb +33 -0
  21. data/lib/moon/application/rack.rb +104 -0
  22. data/lib/moon/application/routes.rb +16 -0
  23. data/lib/moon/context.rb +25 -0
  24. data/lib/moon/formatter.rb +22 -0
  25. data/lib/moon/formatter/base.rb +15 -0
  26. data/lib/moon/formatter/generic.rb +29 -0
  27. data/lib/moon/response.rb +7 -0
  28. data/lib/moon/response/base.rb +18 -0
  29. data/lib/moon/response/json.rb +26 -0
  30. data/lib/moon/response/json/collection.rb +12 -0
  31. data/lib/moon/response/json/message.rb +18 -0
  32. data/lib/moon/response/json/model.rb +16 -0
  33. data/lib/moon/response/json/validation_errors.rb +9 -0
  34. data/lib/moon/utility.rb +7 -0
  35. data/lib/moon/utility/string.rb +17 -0
  36. data/lib/moon/utility/template.rb +23 -0
  37. data/lib/moon/validator.rb +71 -0
  38. data/lib/moon/validator/format.rb +32 -0
  39. data/lib/moon/validator/length.rb +42 -0
  40. data/lib/moon/validator/presence.rb +29 -0
  41. data/spec/lib/moon/action/base_spec.rb +29 -0
  42. data/spec/lib/moon/action/model/create_spec.rb +111 -0
  43. data/spec/lib/moon/action/model/destroy_spec.rb +84 -0
  44. data/spec/lib/moon/action/model/index_spec.rb +51 -0
  45. data/spec/lib/moon/action/model/show_spec.rb +51 -0
  46. data/spec/lib/moon/action/model/update_spec.rb +91 -0
  47. data/spec/lib/moon/action/models/finder_spec.rb +36 -0
  48. data/spec/lib/moon/action/models/initializer_spec.rb +43 -0
  49. data/spec/lib/moon/action/models/updater_spec.rb +36 -0
  50. data/spec/lib/moon/action/rebuild_arrays_spec.rb +28 -0
  51. data/spec/lib/moon/action/reference_object_spec.rb +32 -0
  52. data/spec/lib/moon/action/valid_models_required_spec.rb +64 -0
  53. data/spec/lib/moon/application/rack_spec.rb +73 -0
  54. data/spec/lib/moon/application/routes_spec.rb +26 -0
  55. data/spec/lib/moon/context_spec.rb +28 -0
  56. data/spec/lib/moon/formatter/base_spec.rb +30 -0
  57. data/spec/lib/moon/formatter/generic_spec.rb +34 -0
  58. data/spec/lib/moon/formatter_spec.rb +36 -0
  59. data/spec/lib/moon/response/base_spec.rb +33 -0
  60. data/spec/lib/moon/response/json/collection_spec.rb +30 -0
  61. data/spec/lib/moon/response/json/message_spec.rb +30 -0
  62. data/spec/lib/moon/response/json/model_spec.rb +31 -0
  63. data/spec/lib/moon/response/json/validation_errors_spec.rb +21 -0
  64. data/spec/lib/moon/response/json_spec.rb +33 -0
  65. data/spec/lib/moon/utility/string_spec.rb +29 -0
  66. data/spec/lib/moon/utility/template_spec.rb +49 -0
  67. data/spec/lib/moon/validator/format_spec.rb +40 -0
  68. data/spec/lib/moon/validator/length_spec.rb +60 -0
  69. data/spec/lib/moon/validator/presence_spec.rb +45 -0
  70. data/spec/lib/moon/validator_spec.rb +83 -0
  71. data/spec/spec_helper.rb +4 -0
  72. metadata +209 -0
@@ -0,0 +1,12 @@
1
+
2
+ # Moon::Response::JSON::Collection provides a response that contains one single collection.
3
+ class Moon::Response::JSON::Collection < Moon::Response::JSON
4
+
5
+ def initialize(collection)
6
+ @collection = collection.map do |object|
7
+ Moon::Formatter.hash_for object
8
+ end
9
+ super 200, @collection
10
+ end
11
+
12
+ end
@@ -0,0 +1,18 @@
1
+
2
+ # Moon::Response::JSON::Message provides a simple response with one message
3
+ class Moon::Response::JSON::Message < Moon::Response::JSON
4
+
5
+ attr_accessor :message
6
+ attr_accessor :id
7
+
8
+ def initialize(status, message, id = nil)
9
+ @message, @id = message, id
10
+ super status
11
+ end
12
+
13
+ def hash
14
+ id = self.id
15
+ { :message => message }.merge(id ? { :id => id } : { })
16
+ end
17
+
18
+ end
@@ -0,0 +1,16 @@
1
+
2
+ # Moon::Response::JSON::Collection provides a response that contains one single collection.
3
+ class Moon::Response::JSON::Model < Moon::Response::JSON
4
+
5
+ def initialize(key, object)
6
+ @key, @object = key, object
7
+ super 200, hash
8
+ end
9
+
10
+ private
11
+
12
+ def hash
13
+ { @key.to_s => Moon::Formatter.hash_for(@object) }
14
+ end
15
+
16
+ end
@@ -0,0 +1,9 @@
1
+
2
+ # Moon::Response::JSON::ValidationErrors provides a simple response with the validation messages
3
+ class Moon::Response::JSON::ValidationErrors < Moon::Response::JSON
4
+
5
+ def initialize(validation_errors)
6
+ super 200, :validation_errors => validation_errors
7
+ end
8
+
9
+ end
@@ -0,0 +1,7 @@
1
+
2
+ module Moon::Utility
3
+
4
+ autoload :String, File.join(File.dirname(__FILE__), "utility", "string")
5
+ autoload :Template, File.join(File.dirname(__FILE__), "utility", "template")
6
+
7
+ end
@@ -0,0 +1,17 @@
1
+
2
+ module Moon::Utility::String
3
+
4
+ def self.camelize(lower_case_and_underscored_word)
5
+ lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1}".upcase }.gsub(/(?:^|_)(.)/) { $1.upcase }
6
+ end
7
+
8
+ def self.underscore(camel_cased_word)
9
+ camel_cased_word.to_s.
10
+ gsub(/::/, '/').
11
+ gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
12
+ gsub(/([a-z\d])([A-Z])/, '\1_\2').
13
+ tr("-", "_").
14
+ downcase
15
+ end
16
+
17
+ end
@@ -0,0 +1,23 @@
1
+
2
+ module Moon::Utility::Template
3
+
4
+ def self.extended(base)
5
+ base.class_eval do
6
+
7
+ def self.template(*class_attributes)
8
+ @class_attributes = class_attributes
9
+ self.class.send :attr_accessor, *@class_attributes
10
+ end
11
+
12
+ def self.[](*values)
13
+ klass = self.dup
14
+ (@class_attributes || [ ]).each do |class_attribute|
15
+ klass.send :"#{class_attribute}=", values.shift
16
+ end
17
+ klass
18
+ end
19
+
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,71 @@
1
+
2
+ # Generic validator class. Can be used to validate model attributes.
3
+ class Moon::Validator
4
+
5
+ autoload :Format, File.join(File.dirname(__FILE__), "validator", "format")
6
+ autoload :Length, File.join(File.dirname(__FILE__), "validator", "length")
7
+ autoload :Presence, File.join(File.dirname(__FILE__), "validator", "presence")
8
+
9
+ attr_reader :model
10
+
11
+ def initialize(model)
12
+ @model = model
13
+ end
14
+
15
+ def ok?
16
+ perform_checks
17
+ @ok
18
+ end
19
+
20
+ def messages
21
+ perform_checks
22
+ @messages
23
+ end
24
+
25
+ private
26
+
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
31
+ end
32
+ end
33
+
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
40
+ end
41
+ end
42
+
43
+ def add_message(attribute, ok, message)
44
+ return if ok || !message
45
+ @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
69
+ end
70
+
71
+ end
@@ -0,0 +1,32 @@
1
+
2
+ # Value format validator.
3
+ class Moon::Validator::Format
4
+ extend Moon::Utility::Template
5
+
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
18
+ end
19
+
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
30
+ end
31
+
32
+ end
@@ -0,0 +1,42 @@
1
+
2
+ # Value length validator.
3
+ class Moon::Validator::Length
4
+ extend Moon::Utility::Template
5
+
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
23
+ end
24
+
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
40
+ end
41
+
42
+ end
@@ -0,0 +1,29 @@
1
+
2
+ # Value presence validator.
3
+ class Moon::Validator::Presence
4
+
5
+ attr_accessor :value
6
+
7
+ def initialize(value)
8
+ @value = value
9
+ @ok, @message = true, nil
10
+ end
11
+
12
+ def ok?
13
+ check
14
+ @ok
15
+ end
16
+
17
+ def message
18
+ check
19
+ @message
20
+ end
21
+
22
+ private
23
+
24
+ def check
25
+ @ok = @value && @value != ""
26
+ @message = "Must be present." unless @ok
27
+ end
28
+
29
+ end
@@ -0,0 +1,29 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "spec_helper"))
2
+
3
+ describe Moon::Action::Base do
4
+
5
+ before :each do
6
+ @context = mock Moon::Context
7
+
8
+ @action = described_class.new @context
9
+ end
10
+
11
+ describe "context" do
12
+
13
+ it "should return the context" do
14
+ @action.context.should == @context
15
+ end
16
+
17
+ end
18
+
19
+ describe "perform" do
20
+
21
+ it "should raise a #{NotImplementedError}" do
22
+ lambda do
23
+ @action.perform
24
+ end.should raise_error(NotImplementedError)
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,111 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "..", "spec_helper"))
2
+
3
+ describe Moon::Action::Model::Create do
4
+
5
+ before :each do
6
+ @model_class = mock Class, :to_s => "Model"
7
+ @model = mock Object, :class => @model_class
8
+
9
+ @context = Moon::Context.new
10
+ @context.storage_name = :dump
11
+ @context.models[:model] = @model
12
+
13
+ described_class.model_class = @model_class
14
+ @action = described_class.new @context
15
+ end
16
+
17
+ describe "perform" do
18
+
19
+ before :each do
20
+ GOM::Storage.stub :store
21
+ GOM::Object.stub :id => "test:object_1"
22
+
23
+ @model_response = mock Moon::Response::JSON::Model
24
+ Moon::Response::JSON::Model.stub :new => @model_response
25
+
26
+ @message_response = mock Moon::Response::JSON::Message
27
+ Moon::Response::JSON::Message.stub :new => @message_response
28
+ end
29
+
30
+ it "should store the model on the right storage" do
31
+ GOM::Storage.should_receive(:store).with(@model, :dump)
32
+ @action.perform
33
+ end
34
+
35
+ it "should initialize #{Moon::Response::JSON::Model}" do
36
+ Moon::Response::JSON::Model.should_receive(:new).with(:model, @model).and_return(@model_response)
37
+ @action.perform
38
+ end
39
+
40
+ it "should return the model response" do
41
+ response = @action.perform
42
+ response.should == @model_response
43
+ end
44
+
45
+ it "should do nothing if the model isn't initialized" do
46
+ @context.models[:model] = nil
47
+ GOM::Storage.should_not_receive(:store)
48
+ @action.perform
49
+ end
50
+
51
+ it "should initialize the 'failed' message response if the model isn't initialized" do
52
+ @context.models[:model] = nil
53
+ Moon::Response::JSON::Message.should_receive(:new).with(200, "No model initialized.").and_return(@message_response)
54
+ @action.perform
55
+ end
56
+
57
+ it "should return 'failed' message response if the model isn't initialized" do
58
+ @context.models[:model] = nil
59
+ response = @action.perform
60
+ response.should == @message_response
61
+ end
62
+
63
+ end
64
+
65
+ describe "model" do
66
+
67
+ it "should return the model" do
68
+ model = @action.model
69
+ model.should == @model
70
+ end
71
+
72
+ end
73
+
74
+ describe "self.model_symbol" do
75
+
76
+ it "should return the model symbol" do
77
+ model_symbol = described_class.model_symbol
78
+ model_symbol.should == :model
79
+ end
80
+
81
+ end
82
+
83
+ describe "self.model_class" do
84
+
85
+ it "should return the model class" do
86
+ model_class = described_class.model_class
87
+ model_class.should == @model_class
88
+ end
89
+
90
+ end
91
+
92
+ describe "self.[]" do
93
+
94
+ it "should return a class" do
95
+ result = described_class[Object]
96
+ result.should be_instance_of(Class)
97
+ end
98
+
99
+ it "should return a different class" do
100
+ result = described_class[Object]
101
+ result.should_not == described_class
102
+ end
103
+
104
+ it "should return a class connected to the given model class" do
105
+ result = described_class[Object]
106
+ result.model_class.should == Object
107
+ end
108
+
109
+ end
110
+
111
+ end
@@ -0,0 +1,84 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "..", "spec_helper"))
2
+
3
+ describe Moon::Action::Model::Destroy do
4
+
5
+ before :each do
6
+ @model = mock Object
7
+
8
+ @context = Moon::Context.new
9
+ @context.models[:model] = @model
10
+
11
+ described_class.model_symbol = :model
12
+ @action = described_class.new @context
13
+ end
14
+
15
+ describe "perform" do
16
+
17
+ before :each do
18
+ GOM::Storage.stub :remove => nil
19
+ end
20
+
21
+ it "should rmeove the model" do
22
+ GOM::Storage.should_receive(:remove).with(@model)
23
+ @action.perform
24
+ end
25
+
26
+ it "should return 'ok' message response" do
27
+ response = @action.perform
28
+ response.should be_instance_of(Moon::Response::JSON::Message)
29
+ response.status.should == 200
30
+ end
31
+
32
+ it "should do nothing if the model isn't initialized" do
33
+ @context.models[:model] = nil
34
+ GOM::Storage.should_not_receive(:remove)
35
+ @action.perform
36
+ end
37
+
38
+ it "should return 'failed' message response if model isn't initialized" do
39
+ @context.models[:model] = nil
40
+ response = @action.perform
41
+ response.should be_instance_of(Moon::Response::JSON::Message)
42
+ response.status.should == 401
43
+ end
44
+
45
+ end
46
+
47
+ describe "model" do
48
+
49
+ it "should return the model" do
50
+ model = @action.model
51
+ model.should == @model
52
+ end
53
+
54
+ end
55
+
56
+ describe "self.model_symbol" do
57
+
58
+ it "should return the model symbol" do
59
+ model_symbol = described_class.model_symbol
60
+ model_symbol.should == :model
61
+ end
62
+
63
+ end
64
+
65
+ describe "self.[]" do
66
+
67
+ it "should return a class" do
68
+ result = described_class[:model]
69
+ result.should be_instance_of(Class)
70
+ end
71
+
72
+ it "should return a different class" do
73
+ result = described_class[:model]
74
+ result.should_not == described_class
75
+ end
76
+
77
+ it "should return a class connected to the given model symbol" do
78
+ result = described_class[:model]
79
+ result.model_symbol.should == :model
80
+ end
81
+
82
+ end
83
+
84
+ end