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
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
@@ -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