lam 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +8 -16
  3. data/Gemfile +3 -3
  4. data/README.md +17 -19
  5. data/Rakefile +0 -4
  6. data/bin/console +14 -0
  7. data/bin/setup +8 -0
  8. data/lam.gemspec +20 -18
  9. data/lib/lam.rb +1 -10
  10. data/lib/lam/version.rb +1 -1
  11. metadata +21 -189
  12. data/.rspec +0 -2
  13. data/.ruby-version +0 -1
  14. data/Gemfile.lock +0 -107
  15. data/Guardfile +0 -22
  16. data/LICENSE.txt +0 -22
  17. data/bin/lam +0 -14
  18. data/lib/lam/base_controller.rb +0 -54
  19. data/lib/lam/build.rb +0 -43
  20. data/lib/lam/build/handler_generator.rb +0 -34
  21. data/lib/lam/build/lambda_deducer.rb +0 -47
  22. data/lib/lam/build/templates/handler.js +0 -156
  23. data/lib/lam/build/traveling_ruby.rb +0 -108
  24. data/lib/lam/cli.rb +0 -23
  25. data/lib/lam/cli/help.rb +0 -19
  26. data/lib/lam/command.rb +0 -25
  27. data/lib/lam/process.rb +0 -18
  28. data/lib/lam/process/base_processor.rb +0 -23
  29. data/lib/lam/process/controller_processor.rb +0 -36
  30. data/lib/lam/process/help.rb +0 -11
  31. data/lib/lam/process/processor_deducer.rb +0 -52
  32. data/lib/lam/util.rb +0 -13
  33. data/notes/design.md +0 -43
  34. data/notes/traveling-ruby-packaging-lam.md +0 -26
  35. data/notes/traveling-ruby-packaging.md +0 -103
  36. data/notes/traveling-ruby.md +0 -82
  37. data/spec/fixtures/project/.gitignore +0 -3
  38. data/spec/fixtures/project/.ruby-version +0 -1
  39. data/spec/fixtures/project/Gemfile +0 -4
  40. data/spec/fixtures/project/Gemfile.lock +0 -35
  41. data/spec/fixtures/project/app/controllers/application_controller.rb +0 -2
  42. data/spec/fixtures/project/app/controllers/posts_controller.rb +0 -12
  43. data/spec/fixtures/project/bin/lam +0 -22
  44. data/spec/fixtures/project/handlers/controllers/posts.js +0 -156
  45. data/spec/lib/cli_spec.rb +0 -20
  46. data/spec/lib/lam/base_controller_spec.rb +0 -18
  47. data/spec/lib/lam/build/lambda_deducer_spec.rb +0 -20
  48. data/spec/lib/lam/build_spec.rb +0 -29
  49. data/spec/lib/lam/process/controller_processor_spec.rb +0 -22
  50. data/spec/lib/lam/process/infer_spec.rb +0 -24
  51. data/spec/lib/lam/process_spec.rb +0 -18
  52. data/spec/spec_helper.rb +0 -25
data/.rspec DELETED
@@ -1,2 +0,0 @@
1
- --color
2
- --format documentation
@@ -1 +0,0 @@
1
- 2.2.2
@@ -1,107 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- lam (0.0.1)
5
- activesupport
6
- colorize
7
- hashie
8
- thor
9
-
10
- GEM
11
- remote: https://rubygems.org/
12
- specs:
13
- activesupport (5.1.4)
14
- concurrent-ruby (~> 1.0, >= 1.0.2)
15
- i18n (~> 0.7)
16
- minitest (~> 5.1)
17
- tzinfo (~> 1.1)
18
- byebug (9.1.0)
19
- codeclimate-test-reporter (1.0.8)
20
- simplecov (<= 0.13)
21
- coderay (1.1.2)
22
- colorize (0.8.1)
23
- concurrent-ruby (1.0.5)
24
- diff-lcs (1.3)
25
- docile (1.1.5)
26
- ffi (1.9.18)
27
- formatador (0.2.5)
28
- guard (2.14.1)
29
- formatador (>= 0.2.4)
30
- listen (>= 2.7, < 4.0)
31
- lumberjack (~> 1.0)
32
- nenv (~> 0.1)
33
- notiffany (~> 0.0)
34
- pry (>= 0.9.12)
35
- shellany (~> 0.0)
36
- thor (>= 0.18.1)
37
- guard-bundler (2.1.0)
38
- bundler (~> 1.0)
39
- guard (~> 2.2)
40
- guard-compat (~> 1.1)
41
- guard-compat (1.2.1)
42
- guard-rspec (4.7.3)
43
- guard (~> 2.1)
44
- guard-compat (~> 1.1)
45
- rspec (>= 2.99.0, < 4.0)
46
- hashie (3.5.6)
47
- i18n (0.9.0)
48
- concurrent-ruby (~> 1.0)
49
- json (2.1.0)
50
- listen (3.1.5)
51
- rb-fsevent (~> 0.9, >= 0.9.4)
52
- rb-inotify (~> 0.9, >= 0.9.7)
53
- ruby_dep (~> 1.2)
54
- lumberjack (1.0.12)
55
- method_source (0.9.0)
56
- minitest (5.10.3)
57
- nenv (0.3.0)
58
- notiffany (0.1.1)
59
- nenv (~> 0.1)
60
- shellany (~> 0.0)
61
- pry (0.11.2)
62
- coderay (~> 1.1.0)
63
- method_source (~> 0.9.0)
64
- rake (12.2.1)
65
- rb-fsevent (0.10.2)
66
- rb-inotify (0.9.10)
67
- ffi (>= 0.5.0, < 2)
68
- rspec (3.7.0)
69
- rspec-core (~> 3.7.0)
70
- rspec-expectations (~> 3.7.0)
71
- rspec-mocks (~> 3.7.0)
72
- rspec-core (3.7.0)
73
- rspec-support (~> 3.7.0)
74
- rspec-expectations (3.7.0)
75
- diff-lcs (>= 1.2.0, < 2.0)
76
- rspec-support (~> 3.7.0)
77
- rspec-mocks (3.7.0)
78
- diff-lcs (>= 1.2.0, < 2.0)
79
- rspec-support (~> 3.7.0)
80
- rspec-support (3.7.0)
81
- ruby_dep (1.5.0)
82
- shellany (0.0.1)
83
- simplecov (0.13.0)
84
- docile (~> 1.1.0)
85
- json (>= 1.8, < 3)
86
- simplecov-html (~> 0.10.0)
87
- simplecov-html (0.10.2)
88
- thor (0.20.0)
89
- thread_safe (0.3.6)
90
- tzinfo (1.2.3)
91
- thread_safe (~> 0.1)
92
-
93
- PLATFORMS
94
- ruby
95
-
96
- DEPENDENCIES
97
- bundler
98
- byebug
99
- codeclimate-test-reporter
100
- guard
101
- guard-bundler
102
- guard-rspec
103
- lam!
104
- rake
105
-
106
- BUNDLED WITH
107
- 1.15.4
data/Guardfile DELETED
@@ -1,22 +0,0 @@
1
- guard "bundler", cmd: "bundle" do
2
- watch("Gemfile")
3
- watch(/^.+\.gemspec/)
4
- end
5
-
6
- guard :rspec, cmd: "bundle exec rspec" do
7
- require "guard/rspec/dsl"
8
- dsl = Guard::RSpec::Dsl.new(self)
9
-
10
- # RSpec files
11
- rspec = dsl.rspec
12
- watch(rspec.spec_helper) { rspec.spec_dir }
13
- watch(rspec.spec_support) { rspec.spec_dir }
14
- watch(rspec.spec_files)
15
-
16
- # Ruby files
17
- ruby = dsl.ruby
18
- puts "ruby.lib_files #{ruby.lib_files.inspect}"
19
- dsl.watch_spec_files_for(ruby.lib_files)
20
-
21
- watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
22
- end
@@ -1,22 +0,0 @@
1
- Copyright (c) 2013 Tung Nguyen
2
-
3
- MIT License
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/bin/lam DELETED
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- # Trap ^C
4
- Signal.trap("INT") {
5
- puts "\nCtrl-C detected. Exiting..."
6
- sleep 1
7
- exit
8
- }
9
-
10
- $:.unshift(File.expand_path("../../lib", __FILE__))
11
- require "lam"
12
- require "lam/cli"
13
-
14
- Lam::CLI.start(ARGV)
@@ -1,54 +0,0 @@
1
- require 'json'
2
-
3
- module Lam
4
- class BaseController
5
- attr_reader :event, :context
6
- def initialize(event, context)
7
- @event = event
8
- @context = context
9
- end
10
-
11
- # The public methods defined in the user's custom class will become
12
- # lambda functions.
13
- # Returns Example:
14
- # ["FakeController#handler1", "FakeController#handler2"]
15
- def lambda_functions
16
- # public_instance_methods(false) - to not include inherited methods
17
- self.class.public_instance_methods(false) - Object.public_instance_methods
18
- end
19
-
20
- def self.lambda_functions
21
- new(nil, nil).lambda_functions
22
- end
23
-
24
- private
25
- def render(options={})
26
- # render json: {"mytestdata": "value1"}, status: 200, headers: {...}
27
- if options.has_key?(:json)
28
- # Transform the structure to Lambda Proxy structure
29
- # {statusCode: ..., body: ..., headers: }
30
- status = options.delete(:status)
31
- body = options.delete(:json)
32
- result = options.merge(
33
- statusCode: status,
34
- body: body
35
- )
36
- # render text: "text"
37
- elsif options.has_key?(:text)
38
- result = options.delete(:text)
39
- else
40
- raise "Unsupported render option. Only :text and :json supported. options #{options.inspect}"
41
- end
42
-
43
- result
44
- end
45
-
46
- # API Gateway LAMBDA_PROXY wraps the event in its own structure.
47
- # We unwrap the "body" before sending it back
48
- # For regular Lambda function calls, no need to unwrap but need to
49
- # transform it to a string with JSON.dump.
50
- def normalize_event_body(event)
51
- body = event.has_key?("body") ? event["body"] : JSON.dump(event)
52
- end
53
- end
54
- end
@@ -1,43 +0,0 @@
1
- require 'pp'
2
-
3
- class Lam::Build
4
- autoload :LambdaDeducer, "lam/build/lambda_deducer"
5
- autoload :HandlerGenerator, "lam/build/handler_generator"
6
- autoload :TravelingRuby, "lam/build/traveling_ruby"
7
-
8
- def initialize(options)
9
- @options = options
10
- end
11
-
12
- def run
13
- puts "Building project for Lambda..."
14
- build
15
- end
16
-
17
- def build
18
- handlers.each do |handler|
19
- HandlerGenerator.new(handler).generate
20
- end
21
-
22
- TravelingRuby.new.build unless @options[:noop]
23
- end
24
-
25
- def handlers
26
- handlers = []
27
- expression = "#{Lam.root}app/controllers/**/*.rb"
28
- Dir.glob(expression).each do |path|
29
- next unless File.file?(path)
30
- next if path.include?("application_controller.rb")
31
-
32
- path = relative_path(path)
33
- handlers += LambdaDeducer.new(path).deduce.handlers
34
- end
35
- # pp handlers
36
- handlers
37
- end
38
-
39
- # Rids of the Lam.root at beginning
40
- def relative_path(path)
41
- path.sub(Lam.root, '')
42
- end
43
- end
@@ -1,34 +0,0 @@
1
- require "fileutils"
2
- require "erb"
3
-
4
- class Lam::Build
5
- class HandlerGenerator
6
- # handler_info:
7
- # {:handler=>"handlers/controllers/posts.create",
8
- # :js_path=>"handlers/controllers/posts.js",
9
- # :js_method=>"create"}
10
- def initialize(handler_info)
11
- @handler_info = handler_info
12
- @handler = handler_info[:handler]
13
- @js_path = handler_info[:js_path]
14
- @js_method = handler_info[:js_method]
15
- end
16
-
17
- def generate
18
- js_path = "#{Lam.root}#{@js_path}"
19
- FileUtils.mkdir_p(File.dirname(js_path))
20
-
21
- template_path = File.expand_path('../templates/handler.js', __FILE__)
22
- template = IO.read(template_path)
23
-
24
- # Important ERB variables with examples:
25
- # @handler - handlers/controllers/posts.create
26
- # @process_type - controller
27
- @process_type = @handler.split('/')[1].singularize
28
- result = ERB.new(template, nil, "-").result(binding)
29
- puts "generating #{js_path}"
30
- IO.write(js_path, result)
31
- # FileUtils.cp(template_path, js_path)
32
- end
33
- end
34
- end
@@ -1,47 +0,0 @@
1
- class Lam::Build
2
- class LambdaDeducer
3
- attr_reader :handlers
4
- def initialize(path)
5
- @path = path
6
- end
7
-
8
- def run
9
- deduce
10
- end
11
-
12
- def deduce
13
- # Example: require "./app/controllers/posts_controller.rb"
14
- require_path = @path.starts_with?('/') ? @path : "#{Lam.root}#{@path}"
15
- require require_path
16
-
17
- # Example: @klass_name = "PostsController"
18
- @klass_name = File.basename(@path, '.rb').classify
19
- klass = @klass_name.constantize
20
- @handlers = klass.lambda_functions.map { |fn| handler_info(fn) }
21
- self
22
- end
23
-
24
- # Transform the method to the handler info
25
- def handler_info(function_name)
26
- handler = get_handler(function_name)
27
- js_path = get_js_path(function_name)
28
- {
29
- handler: handler,
30
- js_path: js_path,
31
- js_method: function_name.to_s
32
- }
33
- end
34
-
35
- def get_handler(function_name)
36
- "handlers/controllers/#{module_name}.create"
37
- end
38
-
39
- def get_js_path(function_name)
40
- "handlers/controllers/#{module_name}.js"
41
- end
42
-
43
- def module_name
44
- @klass_name.sub(/Controller$/,'').underscore
45
- end
46
- end
47
- end
@@ -1,156 +0,0 @@
1
- 'use strict';
2
-
3
- // handler: <%= @handler %>
4
- const spawn = require('child_process').spawn;
5
-
6
- // Once hooked up to API Gateway can use the curl command to test:
7
- // curl -s -X POST -d @event.json https://endpoint | jq .
8
-
9
- // Filters out lines so only the error lines remain.
10
- // Uses the "RubyError: " marker to find the starting error lines.
11
- //
12
- // Input: String
13
- // random line
14
- // RubyError: RuntimeError: error in submethod
15
- // line1
16
- // line2
17
- // line3
18
- //
19
- // Output: String
20
- // RubyError: RuntimeError: error in submethod
21
- // line1
22
- // line2
23
- // line3
24
- function filterErrorLines(text) {
25
- var lines = text.split("\n")
26
- var markerIndex = lines.findIndex(line => line.startsWith("RubyError: ") )
27
- lines = lines.filter((line, index) => index >= markerIndex )
28
- return lines.join("\n")
29
- }
30
-
31
- // Produces an Error object that displays in the AWS Lambda test console nicely.
32
- // The backtrace are the ruby lines, not the nodejs shim error lines.
33
- // The json payload in the Lambda console looks something like this:
34
- //
35
- // {
36
- // "errorMessage": "RubyError: RuntimeError: error in submethod",
37
- // "errorType": "RubyError",
38
- // "stackTrace": [
39
- // [
40
- // "line1",
41
- // "line2",
42
- // "line3"
43
- // ]
44
- // ]
45
- // }
46
- //
47
- // Input: String
48
- // RubyError: RuntimeError: error in submethod
49
- // line1
50
- // line2
51
- // line3
52
- //
53
- // Output: Error object
54
- // { RubyError: RuntimeError: error in submethod
55
- // line1
56
- // line2
57
- // line3 name: 'RubyError' }
58
- function customError(text) {
59
- text = filterErrorLines(text) // filter for error lines only
60
- var lines = text.split("\n")
61
- var message = lines[0]
62
- var error = new Error(message)
63
- error.name = message.split(':')[0]
64
- error.stack = lines.slice(0, lines.length-1) // drop final empty line
65
- .map(e => e.replace(/^\s+/g,'')) // trim leading whitespaces
66
- .join("\n")
67
- return error
68
- }
69
-
70
- module.exports.<%= @js_method %> = (event, context, callback) => {
71
- // To test on mac, set these environment variables:
72
- // export RUBY_BIN=$HOME/.rbenv/shims/ruby
73
- // export PROCESSOR_COMMAND="lam process controller"
74
-
75
- // Command: lam process controller [event] [context] [handler]
76
- const processor_command = process.env.PROCESSOR_COMMAND || "lam"
77
- var args = [
78
- "process",
79
- "<%= @process_type %>",
80
- JSON.stringify(event),
81
- JSON.stringify(context),
82
- "<%= @handler %>"
83
- ]
84
- // console.log("processor_command %o", processor_command)
85
- // console.log("args %o", args)
86
-
87
- var ruby = spawn("bin/lam", args);
88
-
89
- // string concatation in javascript is faster than array concatation
90
- // http://bit.ly/2gBMDs6
91
- var stdout_buffer = ""; // stdout buffer
92
- // In the processor_command we do NOT call puts directly and write to stdout
93
- // because it will mess up the eventual response that we want API Gateway to
94
- // process.
95
- // The Lambda prints out function to whatever the return value the ruby method
96
- ruby.stdout.on('data', function(data) {
97
- // Not using console.log because it decorates output with a newline.
98
- //
99
- // Uncomment process.stdout.write to see stdout streamed for debugging.
100
- // process.stdout.write(data)
101
- stdout_buffer += data;
102
- });
103
-
104
- // react to potential errors
105
- var stderr_buffer = "";
106
- ruby.stderr.on('data', function(data) {
107
- // not using console.error because it decorates output with a newline
108
- stderr_buffer += data
109
- process.stderr.write(data)
110
- });
111
-
112
- //finalize when ruby process is done.
113
- ruby.on('close', function(exit_code) {
114
- // http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html#nodejs-prog-model-handler-callback
115
-
116
- // succcess
117
- if (exit_code == 0) {
118
- var result
119
- try {
120
- result = JSON.parse(stdout_buffer)
121
- } catch(e) {
122
- // if json cannot be parse assume simple text output intended
123
- process.stderr.write("WARN: error parsing json, assuming plain text is desired.")
124
- result = stdout_buffer
125
- }
126
- callback(null, result);
127
-
128
- // callback(null, stdout_buffer);
129
- } else {
130
-
131
- // TODO: if this works, allow a way to not decorate the error in case
132
- // it actually errors in javascript land
133
- // Customize error object with ruby error info
134
- var error = customError(stderr_buffer)
135
- callback(error);
136
- // console.log("error!")
137
- }
138
- });
139
- }
140
-
141
- // for local testing
142
- if (process.platform == "darwin") {
143
- // fake event and context
144
- var event = {"hello": "world"}
145
- // var event = {"body": {"hello": "world"}} // API Gateway wrapper structure
146
- var context = {"fake": "context"}
147
- module.exports.<%= @js_method %>(event, context, (error, message) => {
148
- console.error("\nLOCAL TESTING OUTPUT")
149
- if (error) {
150
- console.error("error message: %o", error)
151
- } else {
152
- console.error("success message %o", message)
153
- // console.log(JSON.stringify(message)) // stringify
154
- }
155
- })
156
- }