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.
- data/LICENSE +20 -0
- data/README.rdoc +11 -0
- data/Rakefile +48 -0
- data/lib/moon.rb +15 -0
- data/lib/moon/action.rb +12 -0
- data/lib/moon/action/base.rb +16 -0
- data/lib/moon/action/model.rb +10 -0
- data/lib/moon/action/model/create.rb +45 -0
- data/lib/moon/action/model/destroy.rb +42 -0
- data/lib/moon/action/model/index.rb +31 -0
- data/lib/moon/action/model/show.rb +32 -0
- data/lib/moon/action/model/update.rb +42 -0
- data/lib/moon/action/models.rb +8 -0
- data/lib/moon/action/models/finder.rb +43 -0
- data/lib/moon/action/models/initializer.rb +51 -0
- data/lib/moon/action/models/updater.rb +36 -0
- data/lib/moon/action/rebuild_arrays.rb +40 -0
- data/lib/moon/action/reference_object.rb +35 -0
- data/lib/moon/action/valid_models_required.rb +21 -0
- data/lib/moon/application.rb +33 -0
- data/lib/moon/application/rack.rb +104 -0
- data/lib/moon/application/routes.rb +16 -0
- data/lib/moon/context.rb +25 -0
- data/lib/moon/formatter.rb +22 -0
- data/lib/moon/formatter/base.rb +15 -0
- data/lib/moon/formatter/generic.rb +29 -0
- data/lib/moon/response.rb +7 -0
- data/lib/moon/response/base.rb +18 -0
- data/lib/moon/response/json.rb +26 -0
- data/lib/moon/response/json/collection.rb +12 -0
- data/lib/moon/response/json/message.rb +18 -0
- data/lib/moon/response/json/model.rb +16 -0
- data/lib/moon/response/json/validation_errors.rb +9 -0
- data/lib/moon/utility.rb +7 -0
- data/lib/moon/utility/string.rb +17 -0
- data/lib/moon/utility/template.rb +23 -0
- data/lib/moon/validator.rb +71 -0
- data/lib/moon/validator/format.rb +32 -0
- data/lib/moon/validator/length.rb +42 -0
- data/lib/moon/validator/presence.rb +29 -0
- data/spec/lib/moon/action/base_spec.rb +29 -0
- data/spec/lib/moon/action/model/create_spec.rb +111 -0
- data/spec/lib/moon/action/model/destroy_spec.rb +84 -0
- data/spec/lib/moon/action/model/index_spec.rb +51 -0
- data/spec/lib/moon/action/model/show_spec.rb +51 -0
- data/spec/lib/moon/action/model/update_spec.rb +91 -0
- data/spec/lib/moon/action/models/finder_spec.rb +36 -0
- data/spec/lib/moon/action/models/initializer_spec.rb +43 -0
- data/spec/lib/moon/action/models/updater_spec.rb +36 -0
- data/spec/lib/moon/action/rebuild_arrays_spec.rb +28 -0
- data/spec/lib/moon/action/reference_object_spec.rb +32 -0
- data/spec/lib/moon/action/valid_models_required_spec.rb +64 -0
- data/spec/lib/moon/application/rack_spec.rb +73 -0
- data/spec/lib/moon/application/routes_spec.rb +26 -0
- data/spec/lib/moon/context_spec.rb +28 -0
- data/spec/lib/moon/formatter/base_spec.rb +30 -0
- data/spec/lib/moon/formatter/generic_spec.rb +34 -0
- data/spec/lib/moon/formatter_spec.rb +36 -0
- data/spec/lib/moon/response/base_spec.rb +33 -0
- data/spec/lib/moon/response/json/collection_spec.rb +30 -0
- data/spec/lib/moon/response/json/message_spec.rb +30 -0
- data/spec/lib/moon/response/json/model_spec.rb +31 -0
- data/spec/lib/moon/response/json/validation_errors_spec.rb +21 -0
- data/spec/lib/moon/response/json_spec.rb +33 -0
- data/spec/lib/moon/utility/string_spec.rb +29 -0
- data/spec/lib/moon/utility/template_spec.rb +49 -0
- data/spec/lib/moon/validator/format_spec.rb +40 -0
- data/spec/lib/moon/validator/length_spec.rb +60 -0
- data/spec/lib/moon/validator/presence_spec.rb +45 -0
- data/spec/lib/moon/validator_spec.rb +83 -0
- data/spec/spec_helper.rb +4 -0
- 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
|
data/lib/moon/utility.rb
ADDED
@@ -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
|