angus 0.0.1 → 0.0.2

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 (44) hide show
  1. data/bin/angus +13 -0
  2. data/lib/angus.rb +6 -4
  3. data/lib/angus/base.rb +119 -0
  4. data/lib/angus/base_actions.rb +38 -0
  5. data/lib/angus/base_resource.rb +14 -0
  6. data/lib/angus/command.rb +27 -0
  7. data/lib/angus/generator.rb +141 -0
  8. data/lib/angus/generator/templates/Gemfile +5 -0
  9. data/lib/angus/generator/templates/README.md +0 -0
  10. data/lib/angus/generator/templates/config.ru.erb +10 -0
  11. data/lib/angus/generator/templates/definitions/messages.yml +0 -0
  12. data/lib/angus/generator/templates/definitions/operations.yml.erb +21 -0
  13. data/lib/angus/generator/templates/definitions/representations.yml +0 -0
  14. data/lib/angus/generator/templates/definitions/service.yml.erb +3 -0
  15. data/lib/angus/generator/templates/resources/resource.rb.erb +6 -0
  16. data/lib/angus/generator/templates/services/service.rb.erb +4 -0
  17. data/lib/angus/marshallings/base.rb +2 -0
  18. data/lib/angus/marshallings/marshalling.rb +136 -0
  19. data/lib/angus/marshallings/unmarshalling.rb +29 -0
  20. data/lib/angus/renders/base.rb +2 -0
  21. data/lib/angus/renders/html_render.rb +9 -0
  22. data/lib/angus/renders/json_render.rb +15 -0
  23. data/lib/angus/request_handler.rb +62 -0
  24. data/lib/angus/resource_definition.rb +78 -0
  25. data/lib/angus/response.rb +53 -0
  26. data/lib/angus/responses.rb +232 -0
  27. data/lib/angus/rspec/spec_helper.rb +3 -0
  28. data/lib/angus/rspec/support/examples.rb +64 -0
  29. data/lib/angus/rspec/support/examples/describe_errors.rb +36 -0
  30. data/lib/angus/rspec/support/matchers/operation_response_matchers.rb +117 -0
  31. data/lib/angus/rspec/support/operation_response.rb +57 -0
  32. data/lib/angus/utils.rb +2 -0
  33. data/lib/angus/utils/params.rb +24 -0
  34. data/lib/angus/utils/string.rb +27 -0
  35. data/lib/angus/version.rb +2 -2
  36. data/spec/angus/rspec/examples/describe_errors_spec.rb +64 -0
  37. data/spec/spec_helper.rb +27 -0
  38. metadata +181 -19
  39. data/.gitignore +0 -17
  40. data/Gemfile +0 -4
  41. data/LICENSE.txt +0 -22
  42. data/README.md +0 -29
  43. data/Rakefile +0 -1
  44. data/angus.gemspec +0 -23
data/bin/angus ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ # resolve bin path, ignoring symlinks
5
+ require 'pathname'
6
+ bin_file = Pathname.new(__FILE__).realpath
7
+
8
+ # add self to libpath
9
+ $:.unshift File.expand_path('../../lib', bin_file)
10
+
11
+ require 'angus/command'
12
+
13
+ Angus::Command.start
data/lib/angus.rb CHANGED
@@ -1,5 +1,7 @@
1
- require "angus/version"
1
+ # Application external dependencies
2
+ require 'json'
3
+ require 'rack'
2
4
 
3
- module Angus
4
- # Your code goes here...
5
- end
5
+ require_relative 'angus/version'
6
+ require_relative 'angus/utils'
7
+ require_relative 'angus/base'
data/lib/angus/base.rb ADDED
@@ -0,0 +1,119 @@
1
+ require 'json'
2
+ require 'logger'
3
+
4
+ require_relative 'resource_definition'
5
+ require_relative 'request_handler'
6
+ require_relative 'base_resource'
7
+ require_relative 'responses'
8
+
9
+ require_relative 'renders/base'
10
+ require_relative 'marshallings/base'
11
+ require_relative 'base_actions'
12
+
13
+ require 'angus/sdoc'
14
+
15
+ module Angus
16
+ class Base < RequestHandler
17
+ include BaseActions
18
+
19
+ FIRST_VERSION = '0.1'
20
+
21
+ def initialize
22
+ super
23
+
24
+ @resources_definitions = []
25
+ @version = FIRST_VERSION
26
+ @name = self.class.name.downcase
27
+ @configured = false
28
+ @definitions = nil
29
+ @logger = Logger.new(STDOUT)
30
+
31
+ configure!
32
+
33
+ register_base_routes
34
+ register_resources_routes
35
+ end
36
+
37
+ def register_resources_routes
38
+ @resources_definitions.each do |resource|
39
+ register_resource_routes(resource)
40
+ end
41
+ end
42
+
43
+ def configured?
44
+ @configured
45
+ end
46
+
47
+ # TODO ver que hacer
48
+ def configure
49
+ end
50
+
51
+ def configure!
52
+ raise 'Already configured' if configured?
53
+
54
+ # TODO ver como hacer configurable
55
+ @definitions = Angus::SDoc::DefinitionsReader.service_definition('definitions')
56
+
57
+ configure
58
+
59
+ @configured = true
60
+ end
61
+
62
+ def service_code_name
63
+ @definitions.code_name
64
+ end
65
+
66
+ def service_version
67
+ @definitions.version
68
+ end
69
+
70
+ def register(resource_name, options = {})
71
+ resource_definition = ResourceDefinition.new(resource_name, @definitions)
72
+
73
+ @resources_definitions << resource_definition
74
+ end
75
+
76
+ def base_path
77
+ "/#{service_code_name}"
78
+ end
79
+
80
+ def register_resource_routes(resource_definition)
81
+ resource_definition.operations.each do |operation|
82
+ method = operation.method.to_sym
83
+ op_path = "#{api_path}#{operation.path}"
84
+
85
+ response_metadata = resource_definition.build_response_metadata(operation.response_elements)
86
+
87
+ router.on(method, op_path) do |env, params|
88
+ request = Rack::Request.new(env)
89
+ params = Params.indifferent_params(params)
90
+
91
+ resource = resource_definition.resource_class.new(request, params)
92
+
93
+ begin
94
+ response = resource.send(operation.code_name)
95
+
96
+ response = {} unless response.is_a?(Hash)
97
+
98
+ messages = response.delete(:messages)
99
+
100
+ response = build_data_response(response, response_metadata, messages)
101
+
102
+ @response.write(response)
103
+ rescue Exception => error
104
+ status_code = get_error_status_code(error)
105
+ if status_code == Angus::Responses::HTTP_STATUS_CODE_INTERNAL_SERVER_ERROR
106
+ @logger.error("An exception occurs on #{resource.class.name}##{operation.code_name}")
107
+ @logger.error(error)
108
+ end
109
+ response = build_error_response(error)
110
+
111
+ @response.status = status_code
112
+ @response.write(response)
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ end
119
+ end
@@ -0,0 +1,38 @@
1
+ module Angus
2
+ module BaseActions
3
+
4
+ def discover_paths
5
+ {
6
+ 'doc' => doc_path,
7
+ 'api' => api_path
8
+ }
9
+ end
10
+
11
+ def register_base_routes
12
+ router.on(:get, '/') do
13
+ render discover_paths
14
+ end
15
+
16
+ router.on(:get, base_path) do
17
+ render discover_paths
18
+ end
19
+
20
+ router.on(:get, doc_path) do |env, params|
21
+ if params[:format] == 'json'
22
+ render(Angus::SDoc::JsonFormatter.format_service(@definitions), format: :json)
23
+ else
24
+ render(Angus::SDoc::HtmlFormatter.format_service(@definitions), format: :html)
25
+ end
26
+ end
27
+ end
28
+
29
+ def doc_path
30
+ "#{base_path}/doc/#{service_version}"
31
+ end
32
+
33
+ def api_path
34
+ "#{base_path}/api/#{service_version}"
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,14 @@
1
+ require 'yaml'
2
+
3
+ module Angus
4
+ class BaseResource
5
+
6
+ attr_reader :request, :params
7
+
8
+ def initialize(request, params)
9
+ @request = request
10
+ @params = params
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,27 @@
1
+ require 'erb'
2
+ require 'thor'
3
+
4
+ require_relative 'generator'
5
+
6
+ module Angus
7
+ class Command < Thor
8
+
9
+ desc 'new [NAME]', 'Generate a new service'
10
+ def new(name)
11
+ generator.new_service(name)
12
+ end
13
+
14
+ desc 'resource [NAME]', 'Generate a new resource'
15
+ method_option :actions, aliases: '-a', type: :array, desc: 'Generate the given actions for the resource'
16
+ def resource(name)
17
+ generator.resource(name)
18
+ end
19
+
20
+ private
21
+
22
+ def generator
23
+ @generator ||= Angus::Generator.new
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,141 @@
1
+ require 'erb'
2
+ require 'thor'
3
+ require 'thor/actions'
4
+
5
+ module Angus
6
+ class Generator < Thor
7
+ include Thor::Actions
8
+
9
+ RESOURCES_DIR = 'resources'
10
+ DEFINITIONS_DIR = 'definitions'
11
+ SERVICES_DIR = 'services'
12
+
13
+ NEW_APP_DIRECTORIES = %W(#{DEFINITIONS_DIR} #{RESOURCES_DIR} #{SERVICES_DIR})
14
+
15
+ NEW_APP_FILES = %w(
16
+ Gemfile
17
+ config.ru.erb
18
+ services/service.rb.erb
19
+ definitions/messages.yml
20
+ definitions/representations.yml
21
+ definitions/service.yml.erb
22
+ )
23
+
24
+ FILE_MAPPINGS = {
25
+ 'services/service.rb.erb' => -> command, app_name { File.join(SERVICES_DIR, "#{command.underscore(command.classify(app_name))}.rb") },
26
+ 'resources/resource.rb.erb' => -> command, name { "#{command.underscore(command.classify(name))}.rb" },
27
+ 'definitions/operations.yml.erb' => -> command, _ { File.join(command.resource_name, 'operations.yml') }
28
+ }
29
+
30
+ no_commands do
31
+ def new_service(name)
32
+ app_name(name)
33
+
34
+ empty_directory(app_name)
35
+
36
+ NEW_APP_DIRECTORIES.each do |directory|
37
+ empty_directory(File.join(app_name, directory))
38
+ end
39
+
40
+ NEW_APP_FILES.each do |file|
41
+ if is_erb?(file)
42
+ copy_erb_file(file, app_name)
43
+ else
44
+ copy_file(file, File.join(app_name, file))
45
+ end
46
+ end
47
+ end
48
+
49
+ def resource(name)
50
+ resource_name(name)
51
+ resource_actions(options[:actions])
52
+
53
+ empty_directory(RESOURCES_DIR)
54
+ empty_directory(DEFINITIONS_DIR)
55
+
56
+ copy_erb_file('resources/resource.rb.erb', resource_name, RESOURCES_DIR)
57
+ copy_erb_file('definitions/operations.yml.erb', resource_name, DEFINITIONS_DIR)
58
+ insert_into_services(" register :#{resource_name}\n")
59
+ end
60
+
61
+ def app_name(name = nil)
62
+ if name.nil?
63
+ @app_name
64
+ else
65
+ @app_name = name
66
+ end
67
+ end
68
+
69
+ def resource_name(name = nil)
70
+ if name.nil?
71
+ @resource_name
72
+ else
73
+ @resource_name = name
74
+ end
75
+ end
76
+
77
+ def resource_actions(actions = nil)
78
+ if actions.nil?
79
+ @resource_actions || []
80
+ else
81
+ @resource_actions = actions
82
+ end
83
+ end
84
+
85
+ def classify(string)
86
+ string.sub(/^[a-z\d]*/) { $&.capitalize }.gsub(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }.gsub('/', '::')
87
+ end
88
+
89
+ def underscore(camel_cased_word)
90
+ word = camel_cased_word.to_s.dup
91
+ word.gsub!(/::/, '/')
92
+ word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
93
+ word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
94
+ word.tr!('-', '_')
95
+ word.downcase!
96
+ word
97
+ end
98
+ end
99
+
100
+ private
101
+
102
+ def is_erb?(file)
103
+ file.end_with?('.erb')
104
+ end
105
+
106
+ def copy_erb_file(file, name, base_path = nil)
107
+ base_path = name if base_path.nil?
108
+
109
+ tmp_file = Tempfile.new(File.basename(file))
110
+
111
+ source = File.expand_path(find_in_source_paths(file.to_s))
112
+ content = ERB.new(File.binread(source)).result(binding)
113
+
114
+ File.open(tmp_file.path, 'w') { |f| f << content }
115
+ tmp_file.close
116
+
117
+ copy_file(tmp_file.path, File.join(base_path, filename_resolver(file, name)))
118
+ end
119
+
120
+ def insert_into_services(content)
121
+ config = {}
122
+ config.merge!(:after => /def configure\n|def configure .*\n/)
123
+
124
+ file = Dir[File.join(Dir.pwd, SERVICES_DIR, '*.*')].first
125
+
126
+ insert_into_file(file, *([content] << config))
127
+ end
128
+
129
+ def filename_resolver(file, app_name)
130
+ if FILE_MAPPINGS[file].nil?
131
+ file.gsub('.erb', '')
132
+ else
133
+ FILE_MAPPINGS[file].call(self, app_name)
134
+ end
135
+ end
136
+
137
+ end
138
+ end
139
+
140
+ Angus::Generator.source_root(File.join(File.dirname(File.expand_path(__FILE__)), 'generator',
141
+ 'templates'))
@@ -0,0 +1,5 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'rake'
4
+
5
+ gem 'angus', '~> 0.0'
File without changes
@@ -0,0 +1,10 @@
1
+ $: << (File.dirname(__FILE__))
2
+
3
+ require 'bundler'
4
+
5
+ Bundler.setup
6
+
7
+ require 'angus'
8
+ require 'services/<%= app_name %>'
9
+
10
+ run <%= classify(name) %>.new
@@ -0,0 +1,21 @@
1
+ <% resource_actions.each do |action_name| %>
2
+ <%= action_name%>:
3
+ name:
4
+ description: |
5
+
6
+ path:
7
+ method:
8
+ uri:
9
+ - element:
10
+ description:
11
+
12
+ response:
13
+ - element:
14
+ description:
15
+ required:
16
+ type:
17
+
18
+ messages:
19
+ - key:
20
+ description:
21
+ <% end %>
@@ -0,0 +1,3 @@
1
+ service: '<%= classify(app_name) %>'
2
+ code_name: '<%= app_name %>'
3
+ version: '0.1'
@@ -0,0 +1,6 @@
1
+ class <%= classify(resource_name) %> < Angus::BaseResource
2
+ <% resource_actions.each do |action_name| %>
3
+ def <%= action_name %>
4
+ end
5
+ <% end %>
6
+ end
@@ -0,0 +1,4 @@
1
+ class <%= classify(app_name) %> < Angus::Base
2
+ def configure
3
+ end
4
+ end
@@ -0,0 +1,2 @@
1
+ require_relative 'marshalling'
2
+ require_relative 'unmarshalling'