moon 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Philipp Brüll
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
|
2
|
+
= Moon
|
3
|
+
|
4
|
+
No fixed API yet. Documentation will follow...
|
5
|
+
|
6
|
+
== Development
|
7
|
+
|
8
|
+
Development has been done test-driven and the code follows at most the Clean Code paradigms. Code smells has been
|
9
|
+
removed by using the reek[http://github.com/kevinrutherford/reek] code smell detector.
|
10
|
+
|
11
|
+
This project is still experimental and under development. Any bug report and contribution is welcome!
|
data/Rakefile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rake/rdoctask'
|
2
|
+
|
3
|
+
# RSpec
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
RSpec::Core::RakeTask.new do |task|
|
7
|
+
task.rspec_opts = [ "--colour" ]
|
8
|
+
end
|
9
|
+
|
10
|
+
namespace :spec do
|
11
|
+
|
12
|
+
RSpec::Core::RakeTask.new(:profile) do |task|
|
13
|
+
task.rspec_opts = [ "--colour", "--profile" ]
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
# Reek
|
19
|
+
require 'reek/rake/task'
|
20
|
+
|
21
|
+
Reek::Rake::Task.new do |task|
|
22
|
+
task.source_files = "lib/**/*.rb"
|
23
|
+
end
|
24
|
+
|
25
|
+
# RDoc
|
26
|
+
|
27
|
+
desc "Generate the rdoc"
|
28
|
+
Rake::RDocTask.new do |rdoc|
|
29
|
+
rdoc.rdoc_files.add [ "README.rdoc", "lib/**/*.rb" ]
|
30
|
+
rdoc.main = "README.rdoc"
|
31
|
+
rdoc.title = ""
|
32
|
+
end
|
33
|
+
|
34
|
+
# Gem
|
35
|
+
|
36
|
+
namespace :gem do
|
37
|
+
|
38
|
+
desc "Builds the gem"
|
39
|
+
task :build do
|
40
|
+
system "gem build *.gemspec && mkdir -p pkg/ && mv *.gem pkg/"
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "Builds and installs the gem"
|
44
|
+
task :install => :build do
|
45
|
+
system "gem install pkg/"
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
data/lib/moon.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'gom'
|
2
|
+
require 'gom/filesystem-adapter'
|
3
|
+
require 'gom/couchdb-adapter'
|
4
|
+
|
5
|
+
module Moon
|
6
|
+
|
7
|
+
autoload :Action, File.join(File.dirname(__FILE__), "moon", "action")
|
8
|
+
autoload :Application, File.join(File.dirname(__FILE__), "moon", "application")
|
9
|
+
autoload :Context, File.join(File.dirname(__FILE__), "moon", "context")
|
10
|
+
autoload :Formatter, File.join(File.dirname(__FILE__), "moon", "formatter")
|
11
|
+
autoload :Response, File.join(File.dirname(__FILE__), "moon", "response")
|
12
|
+
autoload :Utility, File.join(File.dirname(__FILE__), "moon", "utility")
|
13
|
+
autoload :Validator, File.join(File.dirname(__FILE__), "moon", "validator")
|
14
|
+
|
15
|
+
end
|
data/lib/moon/action.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
|
2
|
+
module Moon::Action
|
3
|
+
|
4
|
+
autoload :Base, File.join(File.dirname(__FILE__), "action", "base")
|
5
|
+
autoload :BuildOptionHashes, File.join(File.dirname(__FILE__), "action", "build_option_hashes")
|
6
|
+
autoload :Model, File.join(File.dirname(__FILE__), "action", "model")
|
7
|
+
autoload :Models, File.join(File.dirname(__FILE__), "action", "models")
|
8
|
+
autoload :RebuildArrays, File.join(File.dirname(__FILE__), "action", "rebuild_arrays")
|
9
|
+
autoload :ReferenceObject, File.join(File.dirname(__FILE__), "action", "reference_object")
|
10
|
+
autoload :ValidModelsRequired, File.join(File.dirname(__FILE__), "action", "valid_models_required")
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
# Base class for all actions. It simply forces subclasses to implement a 'perform' method
|
3
|
+
# and makes the context available.
|
4
|
+
class Moon::Action::Base
|
5
|
+
|
6
|
+
attr_reader :context
|
7
|
+
|
8
|
+
def initialize(context)
|
9
|
+
@context = context
|
10
|
+
end
|
11
|
+
|
12
|
+
def perform
|
13
|
+
raise NotImplementedError, "method perform should be implemented in #{self.class}"
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
|
2
|
+
module Moon::Action::Model
|
3
|
+
|
4
|
+
autoload :Create, File.join(File.dirname(__FILE__), "model", "create")
|
5
|
+
autoload :Destroy, File.join(File.dirname(__FILE__), "model", "destroy")
|
6
|
+
autoload :Index, File.join(File.dirname(__FILE__), "model", "index")
|
7
|
+
autoload :Show, File.join(File.dirname(__FILE__), "model", "show")
|
8
|
+
autoload :Update, File.join(File.dirname(__FILE__), "model", "update")
|
9
|
+
|
10
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
|
2
|
+
# Generic model create action. Stores the initialized model to the configured storage.
|
3
|
+
class Moon::Action::Model::Create
|
4
|
+
|
5
|
+
def initialize(context)
|
6
|
+
@context = context
|
7
|
+
end
|
8
|
+
|
9
|
+
def perform
|
10
|
+
model = self.model
|
11
|
+
if model
|
12
|
+
GOM::Storage.store model, @context.storage_name
|
13
|
+
Moon::Response::JSON::Model.new self.class.model_symbol, model
|
14
|
+
else
|
15
|
+
Moon::Response::JSON::Message.new 200, "No model initialized."
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def model
|
20
|
+
@context.models[self.class.model_symbol]
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.model_symbol
|
24
|
+
Moon::Utility::String.underscore(model_class.to_s).split("/").last.to_sym
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.model_class=(value)
|
28
|
+
@model_class = value
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.model_class
|
32
|
+
@model_class
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.perform(context)
|
36
|
+
new(context).perform
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.[](model_class)
|
40
|
+
klass = self.dup
|
41
|
+
klass.model_class = model_class
|
42
|
+
klass
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
# Generic model destroy action. Removes the specified model from the storage.
|
3
|
+
class Moon::Action::Model::Destroy
|
4
|
+
|
5
|
+
def initialize(context)
|
6
|
+
@context = context
|
7
|
+
end
|
8
|
+
|
9
|
+
def perform
|
10
|
+
model = self.model
|
11
|
+
model_class = model.class
|
12
|
+
if model
|
13
|
+
GOM::Storage.remove model
|
14
|
+
Moon::Response::JSON::Message.new 200, "#{model_class} destroyed."
|
15
|
+
else
|
16
|
+
Moon::Response::JSON::Message.new 401, "#{model_class} destruction failed."
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def model
|
21
|
+
@context.models[self.class.model_symbol]
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.model_symbol=(value)
|
25
|
+
@model_symbol = value
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.model_symbol
|
29
|
+
@model_symbol
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.perform(context)
|
33
|
+
new(context).perform
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.[](model_symbol)
|
37
|
+
klass = self.dup
|
38
|
+
klass.model_symbol = model_symbol
|
39
|
+
klass
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
# Common model index action
|
3
|
+
class Moon::Action::Model::Index
|
4
|
+
|
5
|
+
def initialize(context)
|
6
|
+
@context = context
|
7
|
+
end
|
8
|
+
|
9
|
+
def perform
|
10
|
+
Moon::Response::JSON::Collection.new @context.collections[self.class.collection_key]
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.collection_key=(value)
|
14
|
+
@collection_key = value
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.collection_key
|
18
|
+
@collection_key
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.perform(context)
|
22
|
+
new(context).perform
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.[](collection_key)
|
26
|
+
klass = self.dup
|
27
|
+
klass.collection_key = collection_key
|
28
|
+
klass
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
# Common model show action
|
3
|
+
class Moon::Action::Model::Show
|
4
|
+
|
5
|
+
def initialize(context)
|
6
|
+
@context = context
|
7
|
+
end
|
8
|
+
|
9
|
+
def perform
|
10
|
+
model_key = self.class.model_key
|
11
|
+
Moon::Response::JSON::Model.new model_key, @context.models[model_key]
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.model_key=(value)
|
15
|
+
@model_key = value
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.model_key
|
19
|
+
@model_key
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.perform(context)
|
23
|
+
new(context).perform
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.[](model_key)
|
27
|
+
klass = self.dup
|
28
|
+
klass.model_key = model_key
|
29
|
+
klass
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
# Generic model update action. Stores the specified model to the storage.
|
3
|
+
class Moon::Action::Model::Update
|
4
|
+
|
5
|
+
def initialize(context)
|
6
|
+
@context = context
|
7
|
+
end
|
8
|
+
|
9
|
+
def perform
|
10
|
+
model = self.model
|
11
|
+
if model
|
12
|
+
storage_name = GOM::Object.storage_name model
|
13
|
+
GOM::Storage.store model, storage_name
|
14
|
+
Moon::Response::JSON::Message.new 200, "#{@model_symbol} updated."
|
15
|
+
else
|
16
|
+
Moon::Response::JSON::Message.new 401, "#{@model_symbol} update failed."
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def model
|
21
|
+
@context.models[self.class.model_symbol]
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.model_symbol=(value)
|
25
|
+
@model_symbol = value
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.model_symbol
|
29
|
+
@model_symbol
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.perform(context)
|
33
|
+
new(context).perform
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.[](model_symbol)
|
37
|
+
klass = self.dup
|
38
|
+
klass.model_symbol = model_symbol
|
39
|
+
klass
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
|
2
|
+
module Moon::Action::Models
|
3
|
+
|
4
|
+
autoload :Finder, File.join(File.dirname(__FILE__), "models", "finder")
|
5
|
+
autoload :Initializer, File.join(File.dirname(__FILE__), "models", "initializer")
|
6
|
+
autoload :Updater, File.join(File.dirname(__FILE__), "models", "updater")
|
7
|
+
|
8
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
|
2
|
+
# This action takes parameters that ends with '_id' out of the context and searches the fitting model
|
3
|
+
# for it. The result is assign to the context.
|
4
|
+
class Moon::Action::Models::Finder
|
5
|
+
|
6
|
+
def initialize(context)
|
7
|
+
@context = context
|
8
|
+
end
|
9
|
+
|
10
|
+
def perform
|
11
|
+
find_models
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def find_models
|
18
|
+
@context.parameters.each do |key, value|
|
19
|
+
find_model key, value if self.class.point_to_model?(key)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def find_model(key, id)
|
24
|
+
model_name = self.class.model_name key
|
25
|
+
model = GOM::Storage.fetch id
|
26
|
+
@context.models[model_name.downcase.to_sym] = model
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.perform(context)
|
30
|
+
new(context).perform
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def self.point_to_model?(key)
|
36
|
+
key.to_s =~ /_id$/
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.model_name(key)
|
40
|
+
key.to_s.sub(/_id$/, "").capitalize
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
|
2
|
+
# This action searches for hash values in the parameters and tries to initialize
|
3
|
+
# a model from it.
|
4
|
+
class Moon::Action::Models::Initializer
|
5
|
+
|
6
|
+
def self.perform(context)
|
7
|
+
initialize_models context
|
8
|
+
nil
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def self.initialize_models(context)
|
14
|
+
context.parameters.each do |key, value|
|
15
|
+
context.models[key.to_sym] = Builder.new(key, value).model
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Build a model out of the key and the hash
|
20
|
+
class Builder
|
21
|
+
|
22
|
+
def initialize(key, attributes)
|
23
|
+
@key, @attributes = key, attributes
|
24
|
+
end
|
25
|
+
|
26
|
+
def model
|
27
|
+
fetch_model_class
|
28
|
+
initialize_model
|
29
|
+
set_model_attributes
|
30
|
+
@model
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def fetch_model_class
|
36
|
+
@model_class = Object.const_get(Moon::Utility::String.camelize(@key.to_s))
|
37
|
+
end
|
38
|
+
|
39
|
+
def initialize_model
|
40
|
+
@model = @model_class.new
|
41
|
+
end
|
42
|
+
|
43
|
+
def set_model_attributes
|
44
|
+
@attributes.each do |key, value|
|
45
|
+
@model.send :"#{key}=", value
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|