From 7fc0d81790aa960135dbe9bc5004f7277ce73075 Mon Sep 17 00:00:00 2001 From: Nerbyk Date: Sun, 20 Aug 2023 12:02:09 +0700 Subject: [PATCH 1/8] introduce-basic-multi-gem-repo-structure --- .ruby-version | 1 - CHANGELOG.md | 43 ---- Steepfile | 21 -- .../.github}/workflows/CI.yml | 0 .../.github}/workflows/lint.yml | 0 .../activefunction-core/.gitignore | 0 .../activefunction-core/.rbnextrc | 0 .../activefunction-core/.rubocop.yml | 0 gems/activefunction-core/CHANGELOG.md | 1 + Gemfile => gems/activefunction-core/Gemfile | 0 .../activefunction-core/README.md | 1 - Rakefile => gems/activefunction-core/Rakefile | 0 gems/activefunction-core/Steepfile | 9 + .../active_function_core.gemspec | 27 +-- {bin => gems/activefunction-core/bin}/console | 0 {bin => gems/activefunction-core/bin}/rake | 0 {bin => gems/activefunction-core/bin}/setup | 0 .../activefunction-core/gemfiles}/rbs.gemfile | 0 .../gemfiles}/rubocop.gemfile | 0 gems/activefunction-core/lib/.rbnext/.keep | 0 .../lib/active_function_core.rb | 3 +- .../lib/active_function_core}/version.rb | 2 +- .../sig/active_function_core.rbs | 0 .../aws_events/apiGatewayAuthorizerEvent.rbs | 7 + .../sig/aws_events/apiGatewayV2HTTPEvent.rbs | 83 ++++++++ .../sig/aws_events/awsCongigEvent.rbs | 14 ++ .../sig/aws_events/cloudWatchLogsEvent.rbs | 24 +++ .../sig/aws_events/codeCommitEvent.rbs | 27 +++ .../sig/aws_events/cognitoEvent.rbs | 17 ++ .../sig/aws_events/dynamoDBEvent.rbs | 32 +++ .../sig/aws_events/kinesisEvent.rbs | 18 ++ .../sig/aws_events/kinesisFirehoseEvent.rbs | 21 ++ .../sig/aws_events/s3Event.rbs | 33 +++ .../sig/aws_events/sesEvent.rbs | 61 ++++++ .../sig/aws_events/snsEvent.rbs | 26 +++ .../sig/aws_events/sqsEvent.rbs | 22 ++ gems/activefunction-core/sig/manifest.yml | 2 + .../test/active_function_core_test.rb | 9 + .../activefunction-core/test}/test_helper.rb | 4 +- .../functions/strong_parameters.rb | 104 --------- .../3.0/active_function/functions/core.rb | 49 ----- .../3.0/active_function/functions/response.rb | 30 --- lib/active_function/base.rb | 20 -- lib/active_function/functions/callbacks.rb | 69 ------ lib/active_function/functions/core.rb | 49 ----- lib/active_function/functions/rendering.rb | 31 --- lib/active_function/functions/response.rb | 30 --- .../functions/strong_parameters.rb | 104 --------- sig/active_function/base.rbs | 14 -- sig/active_function/functions/callbacks.rbs | 42 ---- sig/active_function/functions/core.rbs | 34 --- sig/active_function/functions/rendering.rbs | 20 -- sig/active_function/functions/response.rbs | 18 -- .../functions/strong_parameters.rbs | 49 ----- sig/aws_events/apiGatewayAuthorizerEvent.rbs | 5 - sig/aws_events/apiGatewayV2HTTPEvent.rbs | 81 ------- sig/aws_events/awsCongigEvent.rbs | 12 -- sig/aws_events/cloudWatchLogsEvent.rbs | 22 -- sig/aws_events/codeCommitEvent.rbs | 25 --- sig/aws_events/cognitoEvent.rbs | 15 -- sig/aws_events/dynamoDBEvent.rbs | 30 --- sig/aws_events/kinesisEvent.rbs | 16 -- sig/aws_events/kinesisFirehoseEvent.rbs | 19 -- sig/aws_events/s3Event.rbs | 31 --- sig/aws_events/sesEvent.rbs | 59 ------ sig/aws_events/snsEvent.rbs | 25 --- sig/aws_events/sqsEvent.rbs | 20 -- sig/manifest.yml | 3 - sig/typeprof.rb | 21 -- test/active_function_test.rb | 73 ------- .../fixtures/aws_events/api_gateway_http.json | 101 --------- test/fixtures/aws_events/dynamodb.json | 64 ------ test/functions/callbacks_test.rb | 171 --------------- test/functions/core_test.rb | 40 ---- test/functions/rendering_test.rb | 90 -------- test/functions/response_test.rb | 43 ---- test/functions/strong_parameters_test.rb | 200 ------------------ test/support/active_function_helper.rb | 13 -- 78 files changed, 417 insertions(+), 1933 deletions(-) delete mode 100644 .ruby-version delete mode 100644 CHANGELOG.md delete mode 100644 Steepfile rename {.github => gems/activefunction-core/.github}/workflows/CI.yml (100%) rename {.github => gems/activefunction-core/.github}/workflows/lint.yml (100%) rename .gitignore => gems/activefunction-core/.gitignore (100%) rename .rbnextrc => gems/activefunction-core/.rbnextrc (100%) rename .rubocop.yml => gems/activefunction-core/.rubocop.yml (100%) create mode 100644 gems/activefunction-core/CHANGELOG.md rename Gemfile => gems/activefunction-core/Gemfile (100%) rename README.md => gems/activefunction-core/README.md (99%) rename Rakefile => gems/activefunction-core/Rakefile (100%) create mode 100644 gems/activefunction-core/Steepfile rename activefunction.gemspec => gems/activefunction-core/active_function_core.gemspec (60%) rename {bin => gems/activefunction-core/bin}/console (100%) rename {bin => gems/activefunction-core/bin}/rake (100%) rename {bin => gems/activefunction-core/bin}/setup (100%) rename {gemfiles => gems/activefunction-core/gemfiles}/rbs.gemfile (100%) rename {gemfiles => gems/activefunction-core/gemfiles}/rubocop.gemfile (100%) create mode 100644 gems/activefunction-core/lib/.rbnext/.keep rename lib/active_function.rb => gems/activefunction-core/lib/active_function_core.rb (74%) rename {lib/active_function => gems/activefunction-core/lib/active_function_core}/version.rb (74%) rename sig/active_function.rbs => gems/activefunction-core/sig/active_function_core.rbs (100%) create mode 100644 gems/activefunction-core/sig/aws_events/apiGatewayAuthorizerEvent.rbs create mode 100644 gems/activefunction-core/sig/aws_events/apiGatewayV2HTTPEvent.rbs create mode 100644 gems/activefunction-core/sig/aws_events/awsCongigEvent.rbs create mode 100644 gems/activefunction-core/sig/aws_events/cloudWatchLogsEvent.rbs create mode 100644 gems/activefunction-core/sig/aws_events/codeCommitEvent.rbs create mode 100644 gems/activefunction-core/sig/aws_events/cognitoEvent.rbs create mode 100644 gems/activefunction-core/sig/aws_events/dynamoDBEvent.rbs create mode 100644 gems/activefunction-core/sig/aws_events/kinesisEvent.rbs create mode 100644 gems/activefunction-core/sig/aws_events/kinesisFirehoseEvent.rbs create mode 100644 gems/activefunction-core/sig/aws_events/s3Event.rbs create mode 100644 gems/activefunction-core/sig/aws_events/sesEvent.rbs create mode 100644 gems/activefunction-core/sig/aws_events/snsEvent.rbs create mode 100644 gems/activefunction-core/sig/aws_events/sqsEvent.rbs create mode 100644 gems/activefunction-core/sig/manifest.yml create mode 100644 gems/activefunction-core/test/active_function_core_test.rb rename {test => gems/activefunction-core/test}/test_helper.rb (76%) delete mode 100644 lib/.rbnext/2.7/active_function/functions/strong_parameters.rb delete mode 100644 lib/.rbnext/3.0/active_function/functions/core.rb delete mode 100644 lib/.rbnext/3.0/active_function/functions/response.rb delete mode 100644 lib/active_function/base.rb delete mode 100644 lib/active_function/functions/callbacks.rb delete mode 100644 lib/active_function/functions/core.rb delete mode 100644 lib/active_function/functions/rendering.rb delete mode 100644 lib/active_function/functions/response.rb delete mode 100644 lib/active_function/functions/strong_parameters.rb delete mode 100644 sig/active_function/base.rbs delete mode 100644 sig/active_function/functions/callbacks.rbs delete mode 100644 sig/active_function/functions/core.rbs delete mode 100644 sig/active_function/functions/rendering.rbs delete mode 100644 sig/active_function/functions/response.rbs delete mode 100644 sig/active_function/functions/strong_parameters.rbs delete mode 100644 sig/aws_events/apiGatewayAuthorizerEvent.rbs delete mode 100644 sig/aws_events/apiGatewayV2HTTPEvent.rbs delete mode 100644 sig/aws_events/awsCongigEvent.rbs delete mode 100644 sig/aws_events/cloudWatchLogsEvent.rbs delete mode 100644 sig/aws_events/codeCommitEvent.rbs delete mode 100644 sig/aws_events/cognitoEvent.rbs delete mode 100644 sig/aws_events/dynamoDBEvent.rbs delete mode 100644 sig/aws_events/kinesisEvent.rbs delete mode 100644 sig/aws_events/kinesisFirehoseEvent.rbs delete mode 100644 sig/aws_events/s3Event.rbs delete mode 100644 sig/aws_events/sesEvent.rbs delete mode 100644 sig/aws_events/snsEvent.rbs delete mode 100644 sig/aws_events/sqsEvent.rbs delete mode 100644 sig/manifest.yml delete mode 100644 sig/typeprof.rb delete mode 100644 test/active_function_test.rb delete mode 100644 test/fixtures/aws_events/api_gateway_http.json delete mode 100644 test/fixtures/aws_events/dynamodb.json delete mode 100644 test/functions/callbacks_test.rb delete mode 100644 test/functions/core_test.rb delete mode 100644 test/functions/rendering_test.rb delete mode 100644 test/functions/response_test.rb delete mode 100644 test/functions/strong_parameters_test.rb delete mode 100644 test/support/active_function_helper.rb diff --git a/.ruby-version b/.ruby-version deleted file mode 100644 index ff365e0..0000000 --- a/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -3.1.3 diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index f3d2b49..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,43 +0,0 @@ -## [Unreleased] - -## [0.1.0] - 2022-12-28 - -- Add `before_action` and `after_action` callbacks with `:only` and `:if` options -- Add `ActiveFunction::Base#params` with `require`, `permit`, `[]` and `to_h` public methods -- Add specs for `ActiveFunction::Base.params` module -- Add `ActiveFunction::Base#render` with `:status`, `:json` and `:head` options -- Add RBS signature -- Add RBS Aws Event Types -- Add public interface type `steep` checking -- Add `ruby-next` transpiler - -## [0.2.0] - 2023-01-08 - -- Add unit tests -- Fix Steep pipeline & add better RBS type signatures -- Refactor `::Functions` module -- Add `Response` class - -## [0.3.0] - 2023-01-12 - -- cleanup -- add ActiveFunction::Functions::Response#commit! -- extract action processing to separate method to handle ActiveFunction::Functions::Callbacks#process overriding -- add test for ActiveFunction::Base.process - - -# [0.3.1] - 2023-02-09 - -- Updated readme -- Make callbacks inheritable -- `include` -> `prepend` Core module - -# [0.3.2] - 2023-02-10 - -- Finish readme -- Fix callbacks broken by `prepend` change -- Add more tests for `#process` public interface - -# [0.3.4] - 2023-05-02 - -- Fix RubyNext runtime integration diff --git a/Steepfile b/Steepfile deleted file mode 100644 index a9135f8..0000000 --- a/Steepfile +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -target :lib do - signature "sig" - - check "lib" - - ignore "lib/active_function/version.rb" - # Temporary disable type checking for this file due to: - # lib/active_function/functions/strong_parameters.rb:94:44: [error] Unsupported splat node occurrence - # │ Diagnostic ID: Ruby::UnsupportedSyntax - # │ - # └ attribute.map { _1.send(method, *options.to_a) } - # ~~~~~~~~~~~~~ - ignore "lib/active_function/functions/strong_parameters.rb" - - library( - "json", - "forwardable" - ) -end diff --git a/.github/workflows/CI.yml b/gems/activefunction-core/.github/workflows/CI.yml similarity index 100% rename from .github/workflows/CI.yml rename to gems/activefunction-core/.github/workflows/CI.yml diff --git a/.github/workflows/lint.yml b/gems/activefunction-core/.github/workflows/lint.yml similarity index 100% rename from .github/workflows/lint.yml rename to gems/activefunction-core/.github/workflows/lint.yml diff --git a/.gitignore b/gems/activefunction-core/.gitignore similarity index 100% rename from .gitignore rename to gems/activefunction-core/.gitignore diff --git a/.rbnextrc b/gems/activefunction-core/.rbnextrc similarity index 100% rename from .rbnextrc rename to gems/activefunction-core/.rbnextrc diff --git a/.rubocop.yml b/gems/activefunction-core/.rubocop.yml similarity index 100% rename from .rubocop.yml rename to gems/activefunction-core/.rubocop.yml diff --git a/gems/activefunction-core/CHANGELOG.md b/gems/activefunction-core/CHANGELOG.md new file mode 100644 index 0000000..701cd4c --- /dev/null +++ b/gems/activefunction-core/CHANGELOG.md @@ -0,0 +1 @@ +## [Unreleased] diff --git a/Gemfile b/gems/activefunction-core/Gemfile similarity index 100% rename from Gemfile rename to gems/activefunction-core/Gemfile diff --git a/README.md b/gems/activefunction-core/README.md similarity index 99% rename from README.md rename to gems/activefunction-core/README.md index c8e65b2..9353e91 100644 --- a/README.md +++ b/gems/activefunction-core/README.md @@ -5,7 +5,6 @@ rails/action_controller like gem which provides lightweight callbacks, strong pa Implemented with some of ruby 3.x features, but also supports ruby 2.6.x thanks to [RubyNext](https://github.com/ruby-next/ruby-next) transpiler. Type safety achieved by RBS and [Steep](https://github.com/soutaro/steep). - ## A Short Example Here's a simple example of a function that uses ActiveFunction: diff --git a/Rakefile b/gems/activefunction-core/Rakefile similarity index 100% rename from Rakefile rename to gems/activefunction-core/Rakefile diff --git a/gems/activefunction-core/Steepfile b/gems/activefunction-core/Steepfile new file mode 100644 index 0000000..aaec516 --- /dev/null +++ b/gems/activefunction-core/Steepfile @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +target :lib do + signature "sig" + + check "lib" + + ignore "lib/active_function/version.rb" +end diff --git a/activefunction.gemspec b/gems/activefunction-core/active_function_core.gemspec similarity index 60% rename from activefunction.gemspec rename to gems/activefunction-core/active_function_core.gemspec index 896e90d..a1d519c 100644 --- a/activefunction.gemspec +++ b/gems/activefunction-core/active_function_core.gemspec @@ -1,32 +1,21 @@ # frozen_string_literal: true -require_relative "lib/active_function/version" +require_relative "lib/active_function_core/version" Gem::Specification.new do |spec| - spec.name = "activefunction" + spec.name = "active_function_core" spec.version = ActiveFunction::VERSION spec.authors = ["Nerbyk"] spec.email = ["danil.maximov2000@gmail.com"] - spec.summary = %( - rails/action_controller like gem which provides - callbacks, strong parameters & rendering features. - ) - spec.description = %( - rails/action_controller like gem which provides lightweight callbacks, - strong parameters & rendering features. It's designed to be used with - AWS Lambda functions, but can be also used with any Ruby application. - - Implemented with some of ruby 3.x features, but also supports - ruby 2.6.x thanks to RubyNext transpiler. Type safety achieved - by RBS and Steep. - ) - spec.homepage = "https://github.com/DanilMaximov/acitvefunction" + spec.summary = %(ActiveFunction::Core) + spec.description = %(Provides core functionality for ActiveFunction and ruby-next integration) + spec.homepage = "https://github.com/DanilMaximov/acitvefunction/gems/active_function-core" spec.license = "MIT" spec.metadata = { - "homepage_uri" => "https://github.com/DanilMaximov/activefunction", - "source_code_uri" => "https://github.com/DanilMaximov/activefunction", - "changelog_uri" => "https://github.com/DanilMaximov/activefunction/CHANGELOG.md" + "homepage_uri" => "https://github.com/DanilMaximov/activefunction/gems/active_function-core", + "source_code_uri" => "https://github.com/DanilMaximov/activefunction/gems/active_function-core", + "changelog_uri" => "https://github.com/DanilMaximov/activefunction/gems/active_function-core/CHANGELOG.md" } spec.files = Dir.glob("lib/**/*") + Dir.glob("lib/.rbnext/**/*") + Dir.glob("bin/**/*") + %w[sig/active_function.rbs sig/manifest.yml] + %w[README.md LICENSE.txt CHANGELOG.md] diff --git a/bin/console b/gems/activefunction-core/bin/console similarity index 100% rename from bin/console rename to gems/activefunction-core/bin/console diff --git a/bin/rake b/gems/activefunction-core/bin/rake similarity index 100% rename from bin/rake rename to gems/activefunction-core/bin/rake diff --git a/bin/setup b/gems/activefunction-core/bin/setup similarity index 100% rename from bin/setup rename to gems/activefunction-core/bin/setup diff --git a/gemfiles/rbs.gemfile b/gems/activefunction-core/gemfiles/rbs.gemfile similarity index 100% rename from gemfiles/rbs.gemfile rename to gems/activefunction-core/gemfiles/rbs.gemfile diff --git a/gemfiles/rubocop.gemfile b/gems/activefunction-core/gemfiles/rubocop.gemfile similarity index 100% rename from gemfiles/rubocop.gemfile rename to gems/activefunction-core/gemfiles/rubocop.gemfile diff --git a/gems/activefunction-core/lib/.rbnext/.keep b/gems/activefunction-core/lib/.rbnext/.keep new file mode 100644 index 0000000..e69de29 diff --git a/lib/active_function.rb b/gems/activefunction-core/lib/active_function_core.rb similarity index 74% rename from lib/active_function.rb rename to gems/activefunction-core/lib/active_function_core.rb index 3c7a1bc..8b92927 100644 --- a/lib/active_function.rb +++ b/gems/activefunction-core/lib/active_function_core.rb @@ -8,6 +8,5 @@ module ActiveFunction class Error < StandardError; end - require "active_function/version" - require "active_function/base" + require "active_function_core/version" end diff --git a/lib/active_function/version.rb b/gems/activefunction-core/lib/active_function_core/version.rb similarity index 74% rename from lib/active_function/version.rb rename to gems/activefunction-core/lib/active_function_core/version.rb index 0f9f88d..070cf1f 100644 --- a/lib/active_function/version.rb +++ b/gems/activefunction-core/lib/active_function_core/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module ActiveFunction - VERSION = "0.3.4" + VERSION = "0.1.0" end diff --git a/sig/active_function.rbs b/gems/activefunction-core/sig/active_function_core.rbs similarity index 100% rename from sig/active_function.rbs rename to gems/activefunction-core/sig/active_function_core.rbs diff --git a/gems/activefunction-core/sig/aws_events/apiGatewayAuthorizerEvent.rbs b/gems/activefunction-core/sig/aws_events/apiGatewayAuthorizerEvent.rbs new file mode 100644 index 0000000..f43c12d --- /dev/null +++ b/gems/activefunction-core/sig/aws_events/apiGatewayAuthorizerEvent.rbs @@ -0,0 +1,7 @@ +module ActiveFunction + type apiGatewayAuthorizerEvent = { + type: String, + authorizationToken: String, + methodArn: String + } +end diff --git a/gems/activefunction-core/sig/aws_events/apiGatewayV2HTTPEvent.rbs b/gems/activefunction-core/sig/aws_events/apiGatewayV2HTTPEvent.rbs new file mode 100644 index 0000000..8a8a4b6 --- /dev/null +++ b/gems/activefunction-core/sig/aws_events/apiGatewayV2HTTPEvent.rbs @@ -0,0 +1,83 @@ +module ActiveFunction + type apiGatewayV2HTTPEvent = { + version: String, + routeKey: String, + rawPath: String, + rawQueryString: String, + cookies: Array[String], + headers: Hash[Symbol, String], + queryStringParameters: Hash[Symbol, String], + pathParameters: Hash[Symbol, String], + requestContext: apiGatewayV2HTTPRequestContext, + stageVariables: Hash[Symbol, String], + body: String, + isBase64Encoded: bool + } + + type apiGatewayV2HTTPRequestContext = { + accountId: String, + apiId: String, + domainName: String, + domainPrefix: String, + requestId: String, + routeKey: String, + stage: String, + time: String, + timeEpoch: Integer, + authorizer: apiGatewayV2HTTPRequestContextAuthorizer, + http: apiGatewayV2HTTPRequestContextHTTP, + authentication: apiGatewayV2HTTPRequestContextAuthentication, + } + + type apiGatewayV2HTTPRequestContextAuthorizer = { + jwt: apiGatewayV2HTTPRequestContextAuthorizerJWT, + lambda: Hash[Symbol, String], + iam: apiGatewayV2HTTPRequestContextAuthorizerIAM, + } + + type apiGatewayV2HTTPRequestContextAuthorizerJWT = { + claims: Hash[Symbol, String], + scopes: Array[String], + } + + + type apiGatewayV2HTTPRequestContextAuthorizerIAM = { + accessKey: String, + accountId: String, + callerId: String, + cognitoIdentity: apiGatewayV2HTTPRequestContextAuthorizerIAMCognitoIdentity, + principalOrgId: String, + userId: String, + userArn: String, + } + + type apiGatewayV2HTTPRequestContextAuthorizerIAMCognitoIdentity = { + identityId: String, + identityPoolId: String, + } + + type apiGatewayV2HTTPRequestContextHTTP = { + method: String, + path: String, + protocol: String, + sourceIp: String, + userAgent: String, + } + + type apiGatewayV2HTTPRequestContextAuthentication = { + clientCerts: apiGatewayV2HTTPRequestContextAuthenticationClientCert + } + + type apiGatewayV2HTTPRequestContextAuthenticationClientCert = { + clientCertPem: String, + subjectDN: String, + issuerDN: String, + serialNumber: String, + validity: apiGatewayV2HTTPRequestContextAuthenticationClientCertValidity, + } + + type apiGatewayV2HTTPRequestContextAuthenticationClientCertValidity = { + notBefore: String, + notAfter: String, + } +end \ No newline at end of file diff --git a/gems/activefunction-core/sig/aws_events/awsCongigEvent.rbs b/gems/activefunction-core/sig/aws_events/awsCongigEvent.rbs new file mode 100644 index 0000000..daaaa19 --- /dev/null +++ b/gems/activefunction-core/sig/aws_events/awsCongigEvent.rbs @@ -0,0 +1,14 @@ +module ActiveFunction + type awsConfigEvent = { + accountId: String, + configRuleId: String, + configRuleName: String, + configRuleArn: String, + eventLeftScope: bool, + executionRoleArn: String, + invokingEvent: String, + resultToken: String, + ruleParameters: String, + version: String + } +end \ No newline at end of file diff --git a/gems/activefunction-core/sig/aws_events/cloudWatchLogsEvent.rbs b/gems/activefunction-core/sig/aws_events/cloudWatchLogsEvent.rbs new file mode 100644 index 0000000..03970dc --- /dev/null +++ b/gems/activefunction-core/sig/aws_events/cloudWatchLogsEvent.rbs @@ -0,0 +1,24 @@ +module ActiveFunction + type cloudWatchLogsEvent = { + awslogs: cloudWatchLogsRawData + } + + type cloudWatchLogsRawData = { + data: string + } + + type cloudWatchLogsData = { + owner: String, + logGroup: String, + logStream: String, + subscriptionFilters: Array[String], + messageType: String, + logEvents: Array[cloudWatchLogEvent] + } + + type cloudWatchLogEvent = { + id: String, + timestamp: Integer, + message: String + } +end diff --git a/gems/activefunction-core/sig/aws_events/codeCommitEvent.rbs b/gems/activefunction-core/sig/aws_events/codeCommitEvent.rbs new file mode 100644 index 0000000..9c06813 --- /dev/null +++ b/gems/activefunction-core/sig/aws_events/codeCommitEvent.rbs @@ -0,0 +1,27 @@ +module ActiveFunction + type codeCommitEvent = { + Records: Array[codeCommitRecord] + } + + type codeCommitRecord = { + eventID: String, + eventVersion: String, + eventTime: String, + eventTriggerName: String, + eventPartNumber: Integer, + eventName: String, + eventTriggerConfigId: String, + eventSourceARN: String, + codeCommit: Array[codeCommitReference], + userIdentityARN: String, + eventSource: String, + awsRegion: String, + eventTotalParts: Integer, + customData: String, + } + + type codeCommitReference = { + ref: String, + commit: String + } +end \ No newline at end of file diff --git a/gems/activefunction-core/sig/aws_events/cognitoEvent.rbs b/gems/activefunction-core/sig/aws_events/cognitoEvent.rbs new file mode 100644 index 0000000..70918fb --- /dev/null +++ b/gems/activefunction-core/sig/aws_events/cognitoEvent.rbs @@ -0,0 +1,17 @@ +module ActiveFunction + type cognitoEvent = { + version: Integer, + eventType: String, + region: String, + identityPoolId: String, + identityId: String, + datasetName: String, + datasetRecords: Hash[Symbol, cognitoDatasetRecord] + } + + type cognitoDatasetRecord = { + oldValue: String, + newValue: String, + op: String, + } +end diff --git a/gems/activefunction-core/sig/aws_events/dynamoDBEvent.rbs b/gems/activefunction-core/sig/aws_events/dynamoDBEvent.rbs new file mode 100644 index 0000000..fab1632 --- /dev/null +++ b/gems/activefunction-core/sig/aws_events/dynamoDBEvent.rbs @@ -0,0 +1,32 @@ +module ActiveFunction + type dynamoDBEvent = { Records: Array[dynamoDBEventRecord] } + type dynamoDBEventRecord = { + eventID: String, + eventVersion: String, + eventName: String, + eventSource: String, + eventSourceARN: String, + awsRegion: String, + dynamodb: dynamoDBStreamRecord, + } + type dynamoDBStreamRecord = { + Keys: Hash[Symbol, attributeValue], + NewImage: Hash[Symbol, attributeValue], + OldImage: Hash[Symbol, attributeValue], + SequenceNumber: String, + SizeBytes: Integer, + StreamViewType: String + } + type attributeValue = { + B: String, + BOOL: bool, + BS: Array[String], + L: Array[attributeValue], + M: Hash[Symbol, attributeValue], + N: String, + NS: Array[String], + NULL: bool, + S: String, + SS: Array[String] + } +end diff --git a/gems/activefunction-core/sig/aws_events/kinesisEvent.rbs b/gems/activefunction-core/sig/aws_events/kinesisEvent.rbs new file mode 100644 index 0000000..f5fec65 --- /dev/null +++ b/gems/activefunction-core/sig/aws_events/kinesisEvent.rbs @@ -0,0 +1,18 @@ +module ActiveFunction + type kinesisEvent = { Records: Array[kinesisEventRecords] } + type kinesisEventRecords = { + eventID: String, + eventName: String, + eventSource: String, + eventSourceARN: String, + eventVersion: String, + invokeIdentityArn: String, + kinesis: kinesisEventRecord + } + type kinesisEventRecord = { + approximateArrivalTimestamp: Float, + data: String, + partitionKey: String, + sequenceNumber: String + } +end \ No newline at end of file diff --git a/gems/activefunction-core/sig/aws_events/kinesisFirehoseEvent.rbs b/gems/activefunction-core/sig/aws_events/kinesisFirehoseEvent.rbs new file mode 100644 index 0000000..206bad3 --- /dev/null +++ b/gems/activefunction-core/sig/aws_events/kinesisFirehoseEvent.rbs @@ -0,0 +1,21 @@ +module ActiveFunction + type kinesisFirehoseEvent = { + invocationId: String, + deliveryStreamArn: String, + region: String, + records: Array[kinesisFirehoseRecord] + } + type kinesisFirehoseRecord = { + data: String, + recordId: String, + approximateArrivalTimestamp: Integer, + kinesisRecordMetadata: kinesisRecordMetadata + } + type kinesisRecordMetadata = { + shardId: String, + partitionKey: String, + approximateArrivalTimestamp: String, + sequenceNumber: String, + subsequenceNumber: Integer + } +end \ No newline at end of file diff --git a/gems/activefunction-core/sig/aws_events/s3Event.rbs b/gems/activefunction-core/sig/aws_events/s3Event.rbs new file mode 100644 index 0000000..eb968bf --- /dev/null +++ b/gems/activefunction-core/sig/aws_events/s3Event.rbs @@ -0,0 +1,33 @@ +module ActiveFunction + type s3Event = { Records: Array[s3EventRecord] } + type s3EventRecord = { + eventVersion: String, + eventSource: String, + awsRegion: String, + eventTime: String, + eventName: String, + userIdentity: s3UserIdentity, + requestParameters: s3RequestParameters, + responseElements: Hash[String, String], + s3: s3Entity + } + type s3UserIdentity = { principalId: String } + type s3RequestParameters = { sourceIPAddress: String } + type s3Entity = { + schemaVersion: String, + configurationId: String, + bucket: s3Bucket, + object: s3Object + } + type s3Bucket = { + name: String, + ownerIdentity: s3UserIdentity, + arn: String + } + type s3Object = { + key: String, + size: Integer, + eTag: String, + sequencer: String + } +end diff --git a/gems/activefunction-core/sig/aws_events/sesEvent.rbs b/gems/activefunction-core/sig/aws_events/sesEvent.rbs new file mode 100644 index 0000000..74b1698 --- /dev/null +++ b/gems/activefunction-core/sig/aws_events/sesEvent.rbs @@ -0,0 +1,61 @@ +module ActiveFunction + type sesEvent = { + Records: Array[sesRecord] + } + + type sesRecord = { + eventVersion: String, + eventSource: String, + ses: simpleEmailService + } + + type simpleEmailService = { + mail: simpleEmailMessage, + receipt: simpleEmailReceipt + } + + type simpleEmailMessage = { + timestamp: String, + source: String, + messageId: String, + destination: Array[String], + headersTruncated: bool, + headers: Array[sesHeader], + commonHeaders: commonHeaders + } + + type sesHeader = { + name: String, + value: String + } + + type commonHeaders = { + from: Array[String], + to: Array[String], + date: String, + messageId: String, + subject: String + } + + type simpleEmailReceipt = { + recipients: Array[String], + timestamp: String, + spamVerdict: simpleEmailVerdict, + virusVerdict: simpleEmailVerdict, + spfVerdict: simpleEmailVerdict, + dkimVerdict: simpleEmailVerdict, + dmarcVerdict: simpleEmailVerdict, + processingTimeMillis: Integer, + action: simpleEmailAction, + } + + type simpleEmailVerdict = { + status: String + } + + type simpleEmailAction = { + type: String, + topicArn: String, + position: Integer + } +end \ No newline at end of file diff --git a/gems/activefunction-core/sig/aws_events/snsEvent.rbs b/gems/activefunction-core/sig/aws_events/snsEvent.rbs new file mode 100644 index 0000000..4a296ce --- /dev/null +++ b/gems/activefunction-core/sig/aws_events/snsEvent.rbs @@ -0,0 +1,26 @@ +module ActiveFunction + type snsEvent = { Records: Array[snsEventRecords] } + type snsEventRecords = { + EventVersion: String, + EventSubscriptionArn: String, + EventSource: String, + Sns: snsEntity + } + type snsEntity = { + SignatureVersion: String, + Timestamp: String, + Signature: String, + SigningCertUrl: String, + MessageId: String, + Message: String, + MessageAttributes: Hash[Symbol, snsMessageAttributes], + Type: String, + UnsubscribeUrl: String, + TopicArn: String, + Subject: String + } + type snsMessageAttributes = { + Type: String, + Value: String + } +end diff --git a/gems/activefunction-core/sig/aws_events/sqsEvent.rbs b/gems/activefunction-core/sig/aws_events/sqsEvent.rbs new file mode 100644 index 0000000..e3af099 --- /dev/null +++ b/gems/activefunction-core/sig/aws_events/sqsEvent.rbs @@ -0,0 +1,22 @@ +module ActiveFunction + type sqsEvent = { Records: Array[sqsEventRecords] } + type sqsEventRecords = { + messageId: String, + receiptHandle: String, + body: String, + attributes: Hash[Symbol, String], + messageAttributes: Hash[Symbol, sqsMessageAttribute], + md5OfBody: String, + md50fMessageAttributes: String, + eventSource: String, + eventSourceARN: String, + awsRegion: String + } + type sqsMessageAttribute = { + stringValue: String, + binaryValue: String, + stringListValues: Array[String], + binaryListValues: Array[String], + dataType: String + } +end \ No newline at end of file diff --git a/gems/activefunction-core/sig/manifest.yml b/gems/activefunction-core/sig/manifest.yml new file mode 100644 index 0000000..f9cf700 --- /dev/null +++ b/gems/activefunction-core/sig/manifest.yml @@ -0,0 +1,2 @@ +dependencies: + diff --git a/gems/activefunction-core/test/active_function_core_test.rb b/gems/activefunction-core/test/active_function_core_test.rb new file mode 100644 index 0000000..4ed0c16 --- /dev/null +++ b/gems/activefunction-core/test/active_function_core_test.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require "test_helper" + +class ActiveFunctionCoreTest < Minitest::Test + def test_that_it_has_a_version_number + refute_nil ::ActiveFunction::VERSION + end +end diff --git a/test/test_helper.rb b/gems/activefunction-core/test/test_helper.rb similarity index 76% rename from test/test_helper.rb rename to gems/activefunction-core/test/test_helper.rb index e2fc55e..a66ad31 100644 --- a/test/test_helper.rb +++ b/gems/activefunction-core/test/test_helper.rb @@ -6,8 +6,6 @@ require "minitest/autorun" require "minitest/reporters" -require "active_function" - -require "./test/support/active_function_helper" +require "active_function_core" Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new(color: true)] diff --git a/lib/.rbnext/2.7/active_function/functions/strong_parameters.rb b/lib/.rbnext/2.7/active_function/functions/strong_parameters.rb deleted file mode 100644 index 728e392..0000000 --- a/lib/.rbnext/2.7/active_function/functions/strong_parameters.rb +++ /dev/null @@ -1,104 +0,0 @@ -# frozen_string_literal: true - -require "forwardable" - -module ActiveFunction - class ParameterMissingError < Error - MESSAGE_TEMPLATE = "Missing parameter: %s" - - attr_reader :message - - def initialize(param) - MESSAGE_TEMPLATE % param - end - end - - class UnpermittedParameterError < Error - MESSAGE_TEMPLATE = "Unpermitted parameter: %s" - - attr_reader :message - - def initialize(param) - MESSAGE_TEMPLATE % param - end - end - - module Functions - module StrongParameters - def params - @_params ||= Parameters.new(@request) - end - - class Parameters - extend Forwardable - def_delegators :@parameters, :each, :map - include Enumerable - - def initialize(parameters, permitted: false) - @parameters = parameters - @permitted = permitted - end - - def [](attribute) - nested_attribute(parameters[attribute]) - end - - def require(attribute) - value = self[attribute] - - raise ParameterMissingError, attribute if value.nil? - - value - end - - def permit(*attributes) - pparams = {} - - attributes.each do |attribute| - if attribute.is_a? Hash - attribute.each do |k, v| - pparams[k] = process_nested(self[k], :permit, v) - end - else - next unless parameters.key?(attribute) - - pparams[attribute] = self[attribute] - end - end - - Parameters.new(pparams, permitted: true) - end - - def to_h - raise UnpermittedParameterError, parameters.keys unless @permitted - - parameters.transform_values { |_1| process_nested(_1, :to_h) } - end - - private - - def nested_attribute(attribute) - if attribute.is_a? Hash - Parameters.new(attribute) - elsif attribute.is_a?(Array) && attribute[0].is_a?(Hash) - attribute.map { |_1| Parameters.new(_1) } - else - attribute - end - end - - def process_nested(attribute, method, options = []) - if attribute.is_a? Parameters - attribute.send(method, *options) - elsif attribute.is_a?(Array) && attribute[0].is_a?(Parameters) - attribute.map { |_1| _1.send(method, *options) } - else - attribute - end - end - - attr_reader :parameters - end - end - end -end diff --git a/lib/.rbnext/3.0/active_function/functions/core.rb b/lib/.rbnext/3.0/active_function/functions/core.rb deleted file mode 100644 index 1130069..0000000 --- a/lib/.rbnext/3.0/active_function/functions/core.rb +++ /dev/null @@ -1,49 +0,0 @@ -# frozen_string_literal: true - -module ActiveFunction - class MissingRouteMethod < Error - MESSAGE_TEMPLATE = "Missing function route: %s" - - attr_reader :message - - def initialize(context) - @message = MESSAGE_TEMPLATE % context - end - end - - class NotRenderedError < Error - MESSAGE_TEMPLATE = "render was not called: %s" - - attr_reader :message - - def initialize(context) - @message = MESSAGE_TEMPLATE % context - end - end - - module Functions - module Core - attr_reader :action_name, :request, :response - - def dispatch(action_name, request, response) - @action_name = action_name - @request = request - @response = response - - raise MissingRouteMethod, @action_name unless respond_to?(action_name) - - process(@action_name) - - raise NotRenderedError, @action_name unless performed? - - @response.to_h - end - - private - - def process(action) ; public_send(action); end - - def performed? ; @response.committed?; end - end - end -end diff --git a/lib/.rbnext/3.0/active_function/functions/response.rb b/lib/.rbnext/3.0/active_function/functions/response.rb deleted file mode 100644 index 4a67340..0000000 --- a/lib/.rbnext/3.0/active_function/functions/response.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -module ActiveFunction - module Functions - class Response - attr_accessor :status, :headers, :body - - def initialize(status: 200, headers: {}, body: nil) - @status = status - @headers = headers - @body = body - @committed = false - end - - def to_h - { - statusCode: status, - headers: headers, - body: body - } - end - - def commit! - @committed = true - end - - def committed? ; @committed; end - end - end -end diff --git a/lib/active_function/base.rb b/lib/active_function/base.rb deleted file mode 100644 index 5fc9b70..0000000 --- a/lib/active_function/base.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -module ActiveFunction - class Base - require "active_function/functions/core" - require "active_function/functions/callbacks" - require "active_function/functions/strong_parameters" - require "active_function/functions/rendering" - require "active_function/functions/response" - - include Functions::Core - include Functions::Callbacks - include Functions::Rendering - include Functions::StrongParameters - - def self.process(action_name, request = {}, response = Functions::Response.new) - new.dispatch(action_name, request, response) - end - end -end diff --git a/lib/active_function/functions/callbacks.rb b/lib/active_function/functions/callbacks.rb deleted file mode 100644 index d43e021..0000000 --- a/lib/active_function/functions/callbacks.rb +++ /dev/null @@ -1,69 +0,0 @@ -# frozen_string_literal: true - -module ActiveFunction - class MissingCallbackContext < Error - MESSAGE_TEMPLATE = "Missing callback context: %s" - - attr_reader :message - - def initialize(context) - @message = MESSAGE_TEMPLATE % context - end - end - - module Functions - module Callbacks - def self.included(base) - base.extend(ClassMethods) - end - - private - - def process(*) - _run_callbacks :before - - super - - _run_callbacks :after - end - - def _run_callbacks(type) - self.class.callbacks[type].each do |callback_method, options| - raise MissingCallbackContext, callback_method unless respond_to?(callback_method, true) - - send(callback_method) if _executable?(options) - end - end - - def _executable?(options) - return false if options[:only] && !options[:only].include?(@action_name) - return false if options[:if] && !send(options[:if]) - true - end - - module ClassMethods - def inherited(subclass) - subclass.instance_variable_set(:@__callbacks, @__callbacks) - end - - def before_action(method, options = {}) - set_callback :before, method, options - end - - def after_action(method, options = {}) - set_callback :after, method, options - end - - def set_callback(type, method, options = {}) - callbacks[type][method] = options - end - - def callbacks - @__callbacks ||= {before: {}, after: {}} - - @__callbacks - end - end - end - end -end diff --git a/lib/active_function/functions/core.rb b/lib/active_function/functions/core.rb deleted file mode 100644 index 1db2a20..0000000 --- a/lib/active_function/functions/core.rb +++ /dev/null @@ -1,49 +0,0 @@ -# frozen_string_literal: true - -module ActiveFunction - class MissingRouteMethod < Error - MESSAGE_TEMPLATE = "Missing function route: %s" - - attr_reader :message - - def initialize(context) - @message = MESSAGE_TEMPLATE % context - end - end - - class NotRenderedError < Error - MESSAGE_TEMPLATE = "render was not called: %s" - - attr_reader :message - - def initialize(context) - @message = MESSAGE_TEMPLATE % context - end - end - - module Functions - module Core - attr_reader :action_name, :request, :response - - def dispatch(action_name, request, response) - @action_name = action_name - @request = request - @response = response - - raise MissingRouteMethod, @action_name unless respond_to?(action_name) - - process(@action_name) - - raise NotRenderedError, @action_name unless performed? - - @response.to_h - end - - private - - def process(action) = public_send(action) - - def performed? = @response.committed? - end - end -end diff --git a/lib/active_function/functions/rendering.rb b/lib/active_function/functions/rendering.rb deleted file mode 100644 index b9f3edc..0000000 --- a/lib/active_function/functions/rendering.rb +++ /dev/null @@ -1,31 +0,0 @@ -# frozen_string_literal: true - -require "json" - -module ActiveFunction - class DoubleRenderError < Error - MESSAGE_TEMPLATE = "#render was called multiple times in action: %s" - - attr_reader :message - - def initialize(context) - @message = MESSAGE_TEMPLATE % context - end - end - - module Functions - module Rendering - DEFAULT_HEADER = {"Content-Type" => "application/json"}.freeze - - def render(status: 200, json: {}, head: {}) - raise DoubleRenderError, @action_name if performed? - - @response.status = status - @response.headers = head.merge(Hash[DEFAULT_HEADER]) - @response.body = JSON.generate(json) - - @response.commit! - end - end - end -end diff --git a/lib/active_function/functions/response.rb b/lib/active_function/functions/response.rb deleted file mode 100644 index 1c18c0e..0000000 --- a/lib/active_function/functions/response.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -module ActiveFunction - module Functions - class Response - attr_accessor :status, :headers, :body - - def initialize(status: 200, headers: {}, body: nil) - @status = status - @headers = headers - @body = body - @committed = false - end - - def to_h - { - statusCode: status, - headers: headers, - body: body - } - end - - def commit! - @committed = true - end - - def committed? = @committed - end - end -end diff --git a/lib/active_function/functions/strong_parameters.rb b/lib/active_function/functions/strong_parameters.rb deleted file mode 100644 index 097e21d..0000000 --- a/lib/active_function/functions/strong_parameters.rb +++ /dev/null @@ -1,104 +0,0 @@ -# frozen_string_literal: true - -require "forwardable" - -module ActiveFunction - class ParameterMissingError < Error - MESSAGE_TEMPLATE = "Missing parameter: %s" - - attr_reader :message - - def initialize(param) - MESSAGE_TEMPLATE % param - end - end - - class UnpermittedParameterError < Error - MESSAGE_TEMPLATE = "Unpermitted parameter: %s" - - attr_reader :message - - def initialize(param) - MESSAGE_TEMPLATE % param - end - end - - module Functions - module StrongParameters - def params - @_params ||= Parameters.new(@request) - end - - class Parameters - extend Forwardable - def_delegators :@parameters, :each, :map - include Enumerable - - def initialize(parameters, permitted: false) - @parameters = parameters - @permitted = permitted - end - - def [](attribute) - nested_attribute(parameters[attribute]) - end - - def require(attribute) - value = self[attribute] - - raise ParameterMissingError, attribute if value.nil? - - value - end - - def permit(*attributes) - pparams = {} - - attributes.each do |attribute| - if attribute.is_a? Hash - attribute.each do |k, v| - pparams[k] = process_nested(self[k], :permit, v) - end - else - next unless parameters.key?(attribute) - - pparams[attribute] = self[attribute] - end - end - - Parameters.new(pparams, permitted: true) - end - - def to_h - raise UnpermittedParameterError, parameters.keys unless @permitted - - parameters.transform_values { process_nested(_1, :to_h) } - end - - private - - def nested_attribute(attribute) - if attribute.is_a? Hash - Parameters.new(attribute) - elsif attribute.is_a?(Array) && attribute[0].is_a?(Hash) - attribute.map { Parameters.new(_1) } - else - attribute - end - end - - def process_nested(attribute, method, options = []) - if attribute.is_a? Parameters - attribute.send(method, *options) - elsif attribute.is_a?(Array) && attribute[0].is_a?(Parameters) - attribute.map { _1.send(method, *options) } - else - attribute - end - end - - attr_reader :parameters - end - end - end -end diff --git a/sig/active_function/base.rbs b/sig/active_function/base.rbs deleted file mode 100644 index 58b6623..0000000 --- a/sig/active_function/base.rbs +++ /dev/null @@ -1,14 +0,0 @@ -module ActiveFunction - type hash = Hash[untyped, untyped] - - interface _Function - def performed?: -> bool - end - - class Base - extend Functions::Callbacks::ClassMethods - - def self.new: -> Functions::Core - def self.process: (Symbol action_name, ?hash request, ?Functions::Response response) -> Functions::Response::responseHash - end -end diff --git a/sig/active_function/functions/callbacks.rbs b/sig/active_function/functions/callbacks.rbs deleted file mode 100644 index 2c284d1..0000000 --- a/sig/active_function/functions/callbacks.rbs +++ /dev/null @@ -1,42 +0,0 @@ -module ActiveFunction - class MissingCallbackContext < Error - MESSAGE_TEMPLATE: String - - attr_reader message: String - - def initialize: (untyped context) -> void - end - - module Functions - module Callbacks : Base, Core - interface _Callbacks - def callbacks: () -> Hash[Symbol, hash] - end - - include _Function - extend _Callbacks - - type callbackType = :before | :after - - def self.super: () -> singleton(Core) - def process: (*untyped) -> untyped - - private - - def _run_callbacks: (callbackType `type`) -> void - def _executable?: (hash options) -> bool - - module ClassMethods - include _Callbacks - @__callbacks: Hash[Symbol, hash] - - def before_action: (Symbol method, ?hash options) -> void - def after_action: (Symbol method, ?hash options) -> void - def set_callback: (callbackType type, Symbol method, ?hash options) -> void - def inherited: (singleton(Base) subclass) -> void - end - - def self.included: (singleton(Base) base) -> void - end - end -end diff --git a/sig/active_function/functions/core.rbs b/sig/active_function/functions/core.rbs deleted file mode 100644 index 3d77e2a..0000000 --- a/sig/active_function/functions/core.rbs +++ /dev/null @@ -1,34 +0,0 @@ -module ActiveFunction - class MissingRouteMethod < Error - MESSAGE_TEMPLATE: String - - attr_reader message: String - - def initialize: (String context) -> void - end - - class NotRenderedError < Error - MESSAGE_TEMPLATE: String - - attr_reader message: String - - def initialize: (String context) -> void - end - - module Functions - module Core : Base - include _Function - - @performed: bool - @action_name: Symbol - @request: Hash[Symbol, untyped] - @response: Response - - def dispatch: (Symbol action_name, hash request, Response response) -> Response::responseHash - - private - - def process: (Symbol action) -> void - end - end -end diff --git a/sig/active_function/functions/rendering.rbs b/sig/active_function/functions/rendering.rbs deleted file mode 100644 index 07e5c20..0000000 --- a/sig/active_function/functions/rendering.rbs +++ /dev/null @@ -1,20 +0,0 @@ -module ActiveFunction - class DoubleRenderError < Error - MESSAGE_TEMPLATE: String - - attr_reader message: String - - def initialize: (untyped context) -> void - end - - module Functions - module Rendering : Core - include _Function - - DEFAULT_HEADER: Hash[String, String] - @performed: bool - - def render: (?status: ::Integer, ?json: hash, ?head: hash) -> void - end - end -end diff --git a/sig/active_function/functions/response.rbs b/sig/active_function/functions/response.rbs deleted file mode 100644 index f1086b4..0000000 --- a/sig/active_function/functions/response.rbs +++ /dev/null @@ -1,18 +0,0 @@ -module ActiveFunction - module Functions - class Response - type responseHash = {statusCode: Integer, body: String | nil, headers: Hash[String, String]} - - attr_accessor status: Integer - attr_accessor body: String | nil - attr_accessor headers: Hash[String, String] - - @committed: bool - - def initialize: (?status: Integer, ?body: String | nil, ?headers: Hash[String, String]) -> void - def to_h: -> responseHash - def commit!: -> void - def committed?: -> bool - end - end -end diff --git a/sig/active_function/functions/strong_parameters.rbs b/sig/active_function/functions/strong_parameters.rbs deleted file mode 100644 index 7acf700..0000000 --- a/sig/active_function/functions/strong_parameters.rbs +++ /dev/null @@ -1,49 +0,0 @@ -module ActiveFunction - class ParameterMissingError < Error - MESSAGE_TEMPLATE: String - - attr_reader message: String - - def initialize: (untyped param) -> void - end - - class UnpermittedParameterError < Error - MESSAGE_TEMPLATE: String - - attr_reader message: String - - def initialize: (untyped param) -> void - end - - module Functions - module StrongParameters : Core - include _Function - - @_params: Parameters - - def params: -> Parameters - - class Parameters - extend Forwardable - @permitted: bool - @parameters: hash - - def initialize: (hash parameters, ?permitted: bool) -> void - def []: (Symbol attribute) -> (Array[Parameters] | Parameters) - def require: (Symbol attribute) -> (Array[Parameters] | Parameters) - def permit: (*untyped attributes) -> Parameters - def to_h: -> hash - - private - - def nested_attribute: (hash attribute) -> Parameters - | (Array[hash] attribute) -> Array[Parameters] - | (untyped attribute) -> untyped - - def process_nested: (untyped attr, Symbol method, ?Array[Symbol] options) -> (Parameters | Array[Parameters] | untyped) - - attr_reader parameters: hash - end - end - end -end diff --git a/sig/aws_events/apiGatewayAuthorizerEvent.rbs b/sig/aws_events/apiGatewayAuthorizerEvent.rbs deleted file mode 100644 index 254eb9f..0000000 --- a/sig/aws_events/apiGatewayAuthorizerEvent.rbs +++ /dev/null @@ -1,5 +0,0 @@ -type apiGatewayAuthorizerEvent = { - type: String, - authorizationToken: String, - methodArn: String -} diff --git a/sig/aws_events/apiGatewayV2HTTPEvent.rbs b/sig/aws_events/apiGatewayV2HTTPEvent.rbs deleted file mode 100644 index 9ee3ab5..0000000 --- a/sig/aws_events/apiGatewayV2HTTPEvent.rbs +++ /dev/null @@ -1,81 +0,0 @@ -type apiGatewayV2HTTPEvent = { - version: String, - routeKey: String, - rawPath: String, - rawQueryString: String, - cookies: Array[String], - headers: Hash[Symbol, String], - queryStringParameters: Hash[Symbol, String], - pathParameters: Hash[Symbol, String], - requestContext: apiGatewayV2HTTPRequestContext, - stageVariables: Hash[Symbol, String], - body: String, - isBase64Encoded: bool -} - -type apiGatewayV2HTTPRequestContext = { - accountId: String, - apiId: String, - domainName: String, - domainPrefix: String, - requestId: String, - routeKey: String, - stage: String, - time: String, - timeEpoch: Integer, - authorizer: apiGatewayV2HTTPRequestContextAuthorizer, - http: apiGatewayV2HTTPRequestContextHTTP, - authentication: apiGatewayV2HTTPRequestContextAuthentication, -} - -type apiGatewayV2HTTPRequestContextAuthorizer = { - jwt: apiGatewayV2HTTPRequestContextAuthorizerJWT, - lambda: Hash[Symbol, String], - iam: apiGatewayV2HTTPRequestContextAuthorizerIAM, -} - -type apiGatewayV2HTTPRequestContextAuthorizerJWT = { - claims: Hash[Symbol, String], - scopes: Array[String], -} - - -type apiGatewayV2HTTPRequestContextAuthorizerIAM = { - accessKey: String, - accountId: String, - callerId: String, - cognitoIdentity: apiGatewayV2HTTPRequestContextAuthorizerIAMCognitoIdentity, - principalOrgId: String, - userId: String, - userArn: String, -} - -type apiGatewayV2HTTPRequestContextAuthorizerIAMCognitoIdentity = { - identityId: String, - identityPoolId: String, -} - -type apiGatewayV2HTTPRequestContextHTTP = { - method: String, - path: String, - protocol: String, - sourceIp: String, - userAgent: String, -} - -type apiGatewayV2HTTPRequestContextAuthentication = { - clientCerts: apiGatewayV2HTTPRequestContextAuthenticationClientCert -} - -type apiGatewayV2HTTPRequestContextAuthenticationClientCert = { - clientCertPem: String, - subjectDN: String, - issuerDN: String, - serialNumber: String, - validity: apiGatewayV2HTTPRequestContextAuthenticationClientCertValidity, -} - -type apiGatewayV2HTTPRequestContextAuthenticationClientCertValidity = { - notBefore: String, - notAfter: String, -} diff --git a/sig/aws_events/awsCongigEvent.rbs b/sig/aws_events/awsCongigEvent.rbs deleted file mode 100644 index 6781581..0000000 --- a/sig/aws_events/awsCongigEvent.rbs +++ /dev/null @@ -1,12 +0,0 @@ -type awsConfigEvent = { - accountId: String, - configRuleId: String, - configRuleName: String, - configRuleArn: String, - eventLeftScope: bool, - executionRoleArn: String, - invokingEvent: String, - resultToken: String, - ruleParameters: String, - version: String -} diff --git a/sig/aws_events/cloudWatchLogsEvent.rbs b/sig/aws_events/cloudWatchLogsEvent.rbs deleted file mode 100644 index 0faa8a9..0000000 --- a/sig/aws_events/cloudWatchLogsEvent.rbs +++ /dev/null @@ -1,22 +0,0 @@ -type cloudWatchLogsEvent = { - awslogs: cloudWatchLogsRawData -} - -type cloudWatchLogsRawData = { - data: string -} - -type cloudWatchLogsData = { - owner: String, - logGroup: String, - logStream: String, - subscriptionFilters: Array[String], - messageType: String, - logEvents: Array[cloudWatchLogEvent] -} - -type cloudWatchLogEvent = { - id: String, - timestamp: Integer, - message: String -} diff --git a/sig/aws_events/codeCommitEvent.rbs b/sig/aws_events/codeCommitEvent.rbs deleted file mode 100644 index da37694..0000000 --- a/sig/aws_events/codeCommitEvent.rbs +++ /dev/null @@ -1,25 +0,0 @@ -type codeCommitEvent = { - Records: Array[codeCommitRecord] -} - -type codeCommitRecord = { - eventID: String, - eventVersion: String, - eventTime: String, - eventTriggerName: String, - eventPartNumber: Integer, - eventName: String, - eventTriggerConfigId: String, - eventSourceARN: String, - codeCommit: Array[codeCommitReference], - userIdentityARN: String, - eventSource: String, - awsRegion: String, - eventTotalParts: Integer, - customData: String, -} - -type codeCommitReference = { - ref: String, - commit: String -} \ No newline at end of file diff --git a/sig/aws_events/cognitoEvent.rbs b/sig/aws_events/cognitoEvent.rbs deleted file mode 100644 index 0f5468b..0000000 --- a/sig/aws_events/cognitoEvent.rbs +++ /dev/null @@ -1,15 +0,0 @@ -type cognitoEvent = { - version: Integer, - eventType: String, - region: String, - identityPoolId: String, - identityId: String, - datasetName: String, - datasetRecords: Hash[Symbol, cognitoDatasetRecord] -} - -type cognitoDatasetRecord = { - oldValue: String, - newValue: String, - op: String, -} diff --git a/sig/aws_events/dynamoDBEvent.rbs b/sig/aws_events/dynamoDBEvent.rbs deleted file mode 100644 index 62d32f1..0000000 --- a/sig/aws_events/dynamoDBEvent.rbs +++ /dev/null @@ -1,30 +0,0 @@ -type dynamoDBEvent = { Records: Array[dynamoDBEventRecord] } -type dynamoDBEventRecord = { - eventID: String, - eventVersion: String, - eventName: String, - eventSource: String, - eventSourceARN: String, - awsRegion: String, - dynamodb: dynamoDBStreamRecord, -} -type dynamoDBStreamRecord = { - Keys: Hash[Symbol, attributeValue], - NewImage: Hash[Symbol, attributeValue], - OldImage: Hash[Symbol, attributeValue], - SequenceNumber: String, - SizeBytes: Integer, - StreamViewType: String -} -type attributeValue = { - B: String, - BOOL: bool, - BS: Array[String], - L: Array[attributeValue], - M: Hash[Symbol, attributeValue], - N: String, - NS: Array[String], - NULL: bool, - S: String, - SS: Array[String] -} diff --git a/sig/aws_events/kinesisEvent.rbs b/sig/aws_events/kinesisEvent.rbs deleted file mode 100644 index f559d77..0000000 --- a/sig/aws_events/kinesisEvent.rbs +++ /dev/null @@ -1,16 +0,0 @@ -type kinesisEvent = { Records: Array[kinesisEventRecords] } -type kinesisEventRecords = { - eventID: String, - eventName: String, - eventSource: String, - eventSourceARN: String, - eventVersion: String, - invokeIdentityArn: String, - kinesis: kinesisEventRecord -} -type kinesisEventRecord = { - approximateArrivalTimestamp: Float, - data: String, - partitionKey: String, - sequenceNumber: String -} diff --git a/sig/aws_events/kinesisFirehoseEvent.rbs b/sig/aws_events/kinesisFirehoseEvent.rbs deleted file mode 100644 index 81b1c5a..0000000 --- a/sig/aws_events/kinesisFirehoseEvent.rbs +++ /dev/null @@ -1,19 +0,0 @@ -type kinesisFirehoseEvent = { - invocationId: String, - deliveryStreamArn: String, - region: String, - records: Array[kinesisFirehoseRecord] -} -type kinesisFirehoseRecord = { - data: String, - recordId: String, - approximateArrivalTimestamp: Integer, - kinesisRecordMetadata: kinesisRecordMetadata -} -type kinesisRecordMetadata = { - shardId: String, - partitionKey: String, - approximateArrivalTimestamp: String, - sequenceNumber: String, - subsequenceNumber: Integer -} diff --git a/sig/aws_events/s3Event.rbs b/sig/aws_events/s3Event.rbs deleted file mode 100644 index 2be130e..0000000 --- a/sig/aws_events/s3Event.rbs +++ /dev/null @@ -1,31 +0,0 @@ -type s3Event = { Records: Array[s3EventRecord] } -type s3EventRecord = { - eventVersion: String, - eventSource: String, - awsRegion: String, - eventTime: String, - eventName: String, - userIdentity: s3UserIdentity, - requestParameters: s3RequestParameters, - responseElements: Hash[String, String], - s3: s3Entity -} -type s3UserIdentity = { principalId: String } -type s3RequestParameters = { sourceIPAddress: String } -type s3Entity = { - schemaVersion: String, - configurationId: String, - bucket: s3Bucket, - object: s3Object -} -type s3Bucket = { - name: String, - ownerIdentity: s3UserIdentity, - arn: String -} -type s3Object = { - key: String, - size: Integer, - eTag: String, - sequencer: String -} diff --git a/sig/aws_events/sesEvent.rbs b/sig/aws_events/sesEvent.rbs deleted file mode 100644 index 55e00d4..0000000 --- a/sig/aws_events/sesEvent.rbs +++ /dev/null @@ -1,59 +0,0 @@ -type sesEvent = { - Records: Array[sesRecord] -} - -type sesRecord = { - eventVersion: String, - eventSource: String, - ses: simpleEmailService -} - -type simpleEmailService = { - mail: simpleEmailMessage, - receipt: simpleEmailReceipt -} - -type simpleEmailMessage = { - timestamp: String, - source: String, - messageId: String, - destination: Array[String], - headersTruncated: bool, - headers: Array[sesHeader], - commonHeaders: commonHeaders -} - -type sesHeader = { - name: String, - value: String -} - -type commonHeaders = { - from: Array[String], - to: Array[String], - date: String, - messageId: String, - subject: String -} - -type simpleEmailReceipt = { - recipients: Array[String], - timestamp: String, - spamVerdict: simpleEmailVerdict, - virusVerdict: simpleEmailVerdict, - spfVerdict: simpleEmailVerdict, - dkimVerdict: simpleEmailVerdict, - dmarcVerdict: simpleEmailVerdict, - processingTimeMillis: Integer, - action: simpleEmailAction, -} - -type simpleEmailVerdict = { - status: String -} - -type simpleEmailAction = { - type: String, - topicArn: String, - position: Integer -} diff --git a/sig/aws_events/snsEvent.rbs b/sig/aws_events/snsEvent.rbs deleted file mode 100644 index fc0e8c7..0000000 --- a/sig/aws_events/snsEvent.rbs +++ /dev/null @@ -1,25 +0,0 @@ -type snsEvent = { Records: Array[snsEventRecords] } -type snsEventRecords = { - EventVersion: String, - EventSubscriptionArn: String, - EventSource: String, - Sns: snsEntity -} -type snsEntity = { - SignatureVersion: String, - Timestamp: String, - Signature: String, - SigningCertUrl: String, - MessageId: String, - Message: String, - MessageAttributes: Hash[Symbol, snsMessageAttributes], - Type: String, - UnsubscribeUrl: String, - TopicArn: String, - Subject: String -} -type snsMessageAttributes = { - Type: String, - Value: String -} - diff --git a/sig/aws_events/sqsEvent.rbs b/sig/aws_events/sqsEvent.rbs deleted file mode 100644 index 3e99052..0000000 --- a/sig/aws_events/sqsEvent.rbs +++ /dev/null @@ -1,20 +0,0 @@ -type sqsEvent = { Records: Array[sqsEventRecords] } -type sqsEventRecords = { - messageId: String, - receiptHandle: String, - body: String, - attributes: Hash[Symbol, String], - messageAttributes: Hash[Symbol, sqsMessageAttribute], - md5OfBody: String, - md50fMessageAttributes: String, - eventSource: String, - eventSourceARN: String, - awsRegion: String -} -type sqsMessageAttribute = { - stringValue: String, - binaryValue: String, - stringListValues: Array[String], - binaryListValues: Array[String], - dataType: String -} diff --git a/sig/manifest.yml b/sig/manifest.yml deleted file mode 100644 index 014c2aa..0000000 --- a/sig/manifest.yml +++ /dev/null @@ -1,3 +0,0 @@ -dependencies: - - name: json - - name: forwardable diff --git a/sig/typeprof.rb b/sig/typeprof.rb deleted file mode 100644 index 18372f6..0000000 --- a/sig/typeprof.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -require "active_function" - -function = Class.new(ActiveFunction::Base) do - before_action :action, only: :index, if: :condition? - after_action :action, only: :index, if: :condition? - - def index - permitted_params = params.require(:bodt).permit(:name, :id) - render json: permitted_params, status: 200 - end - - private - - def condition? - true - end -end - -function.process(:index, request: {body: {name: "John", id: 1}}) diff --git a/test/active_function_test.rb b/test/active_function_test.rb deleted file mode 100644 index 15887a9..0000000 --- a/test/active_function_test.rb +++ /dev/null @@ -1,73 +0,0 @@ -# frozen_string_literal: true - -require "test_helper" - -class TestFunction < ActiveFunction::Base - def index - render json: {a: 1, b: 2}, status: 201, head: {"X-Test" => "test"} - end -end - -class TestFunctionWithCallbacks < ActiveFunction::Base - before_action :set_first - - def index - render json: {first: @first} - end - - private - - def set_first - @first = 1 - end -end - -class TestFunctionWithParameters < ActiveFunction::Base - def index - render json: params.require(:data).permit(:id, message: %i[text]).to_h - end -end - -class ActiveFunctionTest < Minitest::Test - def test_function_processing - response = TestFunction.process(:index, {}) - - assert_equal(response, { - statusCode: 201, - body: {a: 1, b: 2}.to_json, - headers: {"Content-Type" => "application/json", "X-Test" => "test"} - }) - end - - def test_function_processing_with_callbacks - response = TestFunctionWithCallbacks.process(:index, {}) - - assert_equal(response, { - statusCode: 200, - body: {first: 1}.to_json, - headers: {"Content-Type" => "application/json"} - }) - end - - def test_function_processing_with_inheritted_callbacks - response = Class.new(TestFunctionWithCallbacks).process(:index, {}) - - assert_equal(response, { - statusCode: 200, - body: {first: 1}.to_json, - headers: {"Content-Type" => "application/json"} - }) - end - - def test_function_processing_with_params - data = {data: {id: 1, name: "Pupa", message: {id: 1, text: "test"}}} - - response = TestFunctionWithParameters.process(:index, data) - - assert_equal(response, { - statusCode: 200, - body: {id: 1, message: {text: "test"}}.to_json, - headers: {"Content-Type" => "application/json"} - }) - end -end diff --git a/test/fixtures/aws_events/api_gateway_http.json b/test/fixtures/aws_events/api_gateway_http.json deleted file mode 100644 index 7919cc1..0000000 --- a/test/fixtures/aws_events/api_gateway_http.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "resource": "/", - "path": "/", - "httpMethod": "GET", - "headers": { - "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", - "accept-encoding": "gzip, deflate, br", - "accept-language": "en-US,en;q=0.9", - "cookie": "s_fid=7AAB6XMPLAFD9BBF-0643XMPL09956DE2; regStatus=pre-register", - "Host": "70ixmpl4fl.execute-api.us-east-2.amazonaws.com", - "sec-fetch-dest": "document", - "sec-fetch-mode": "navigate", - "sec-fetch-site": "none", - "upgrade-insecure-requests": "1", - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36", - "X-Amzn-Trace-Id": "Root=1-5e66d96f-7491f09xmpl79d18acf3d050", - "X-Forwarded-For": "52.255.255.12", - "X-Forwarded-Port": "443", - "X-Forwarded-Proto": "https" - }, - "multiValueHeaders": { - "accept": [ - "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" - ], - "accept-encoding": [ - "gzip, deflate, br" - ], - "accept-language": [ - "en-US,en;q=0.9" - ], - "cookie": [ - "s_fid=7AABXMPL1AFD9BBF-0643XMPL09956DE2; regStatus=pre-register;" - ], - "Host": [ - "70ixmpl4fl.execute-api.ca-central-1.amazonaws.com" - ], - "sec-fetch-dest": [ - "document" - ], - "sec-fetch-mode": [ - "navigate" - ], - "sec-fetch-site": [ - "none" - ], - "upgrade-insecure-requests": [ - "1" - ], - "User-Agent": [ - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36" - ], - "X-Amzn-Trace-Id": [ - "Root=1-5e66d96f-7491f09xmpl79d18acf3d050" - ], - "X-Forwarded-For": [ - "52.255.255.12" - ], - "X-Forwarded-Port": [ - "443" - ], - "X-Forwarded-Proto": [ - "https" - ] - }, - "queryStringParameters": null, - "multiValueQueryStringParameters": null, - "pathParameters": null, - "stageVariables": null, - "requestContext": { - "resourceId": "2gxmpl", - "resourcePath": "/", - "httpMethod": "GET", - "extendedRequestId": "JJbxmplHYosFVYQ=", - "requestTime": "10/Mar/2020:00:03:59 +0000", - "path": "/Prod/", - "accountId": "123456789012", - "protocol": "HTTP/1.1", - "stage": "Prod", - "domainPrefix": "70ixmpl4fl", - "requestTimeEpoch": 1583798639428, - "requestId": "77375676-xmpl-4b79-853a-f982474efe18", - "identity": { - "cognitoIdentityPoolId": null, - "accountId": null, - "cognitoIdentityId": null, - "caller": null, - "sourceIp": "52.255.255.12", - "principalOrgId": null, - "accessKey": null, - "cognitoAuthenticationType": null, - "cognitoAuthenticationProvider": null, - "userArn": null, - "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36", - "user": null - }, - "domainName": "70ixmpl4fl.execute-api.us-east-2.amazonaws.com", - "apiId": "70ixmpl4fl" - }, - "body": null, - "isBase64Encoded": false -} diff --git a/test/fixtures/aws_events/dynamodb.json b/test/fixtures/aws_events/dynamodb.json deleted file mode 100644 index 1089670..0000000 --- a/test/fixtures/aws_events/dynamodb.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "Records": [ - { - "eventID": "1", - "eventVersion": "1.0", - "dynamodb": { - "Keys": { - "Id": { - "N": "101" - } - }, - "NewImage": { - "Message": { - "S": "New item!" - }, - "Id": { - "N": "101" - } - }, - "StreamViewType": "NEW_AND_OLD_IMAGES", - "SequenceNumber": "111", - "SizeBytes": 26 - }, - "awsRegion": "us-west-2", - "eventName": "INSERT", - "eventSourceARN": "arn:aws:dynamodb:us-west-2:111122223333:table/TestTable/stream/2015-05-11T21:21:33.291", - "eventSource": "aws:dynamodb" - }, - { - "eventID": "2", - "eventVersion": "1.0", - "dynamodb": { - "OldImage": { - "Message": { - "S": "New item!" - }, - "Id": { - "N": "101" - } - }, - "SequenceNumber": "222", - "Keys": { - "Id": { - "N": "101" - } - }, - "SizeBytes": 59, - "NewImage": { - "Message": { - "S": "This item has changed" - }, - "Id": { - "N": "101" - } - }, - "StreamViewType": "NEW_AND_OLD_IMAGES" - }, - "awsRegion": "us-west-2", - "eventName": "MODIFY", - "eventSourceARN": "arn:aws:dynamodb:us-west-2:111122223333:table/TestTable/stream/2015-05-11T21:21:33.291", - "eventSource": "aws:dynamodb" - } - ] -} \ No newline at end of file diff --git a/test/functions/callbacks_test.rb b/test/functions/callbacks_test.rb deleted file mode 100644 index 79265d9..0000000 --- a/test/functions/callbacks_test.rb +++ /dev/null @@ -1,171 +0,0 @@ -# frozen_string_literal: true - -require "test_helper" - -class CallbackTestFunction - include ActiveFunction::Functions::Core - include ActiveFunction::Functions::Callbacks - - def index - nil - end - - def show - nil - end - - private # callback methods - - def first - @first = "Biba" - end - - def second - @second = "Boba" - end -end - -class CallbackTestFunction1 < CallbackTestFunction - set_callback :before, :first -end - -class CallbackTest1 < Minitest::Test - def setup - @function = CallbackTestFunction1.new - end - - def test_callback - @function.dispatch(:index, {}, committed_response) - - assert_equal @function.instance_variable_get(:@first), "Biba" - end -end - -class CallbackTestFunction2 < CallbackTestFunction - before_action :first - after_action :second -end - -class CallbackTestFunction2Inherit < CallbackTestFunction2 -end - -class CallbackTest2 < Minitest::Test - def setup - @function = CallbackTestFunction2.new - end - - def test_before_action_callback - @function.dispatch(:index, {}, committed_response) - - assert_equal @function.instance_variable_get(:@first), "Biba" - end - - def test_after_action_callback - @function.dispatch(:index, {}, committed_response) - - assert_equal @function.instance_variable_get(:@second), "Boba" - end - - def test_inherit_callbacks - @function = CallbackTestFunction2Inherit.new - - @function.dispatch(:index, {}, committed_response) - - assert_equal @function.instance_variable_get(:@first), "Biba" - assert_equal @function.instance_variable_get(:@second), "Boba" - end -end - -class ConditionalCallbacksTestFunction1 < CallbackTestFunction - before_action :first, only: %i[index] - after_action :second, only: %i[show] -end - -class ConditionalCallbacksTest1 < Minitest::Test - def setup - @function = ConditionalCallbacksTestFunction1.new - end - - def test_before_action_callback - @function.dispatch(:index, {}, committed_response) - - assert_equal @function.instance_variable_get(:@first), "Biba" - assert_nil @function.instance_variable_get(:@second) - end - - def test_after_action_callback - @function.dispatch(:show, {}, committed_response) - - assert_equal @function.instance_variable_get(:@second), "Boba" - end -end - -class ConditionalCallbacksTestFunction2 < CallbackTestFunction - before_action :first, only: %i[show index] -end - -class ConditionalCallbacksTest2 < Minitest::Test - def setup - @function = ConditionalCallbacksTestFunction2.new - end - - def test_callback_for_index_action - @function.dispatch(:index, {}, committed_response) - - assert_equal @function.instance_variable_get(:@first), "Biba" - end - - def test_callback_for_show_action - @function.dispatch(:show, {}, committed_response) - - assert_equal @function.instance_variable_get(:@first), "Biba" - end -end - -class ConditionalCallbacksTestFunction3 < CallbackTestFunction - before_action :first, if: :executable? - after_action :second, if: :not_executable? - - private - - def executable? - false - end - - def not_executable? - true - end -end - -class ConditionalCallbacksTest3 < Minitest::Test - def setup - @function = ConditionalCallbacksTestFunction3.new - end - - def test_if_before_action_callback - @function.dispatch(:index, {}, committed_response) - - assert_nil @function.instance_variable_get(:@first) - assert_equal @function.instance_variable_get(:@second), "Boba" - end -end - -class ConditionalCallbacksTestFunction4 < CallbackTestFunction - before_action :first, only: %i[index], if: :executable? - - private def executable? - true - end -end - -class ConditionalCallbacksTest4 < Minitest::Test - def setup - @function = ConditionalCallbacksTestFunction4.new - end - - def test_callback_with_all_condition_options - @function.dispatch(:index, {}, committed_response) - - assert_equal @function.instance_variable_get(:@first), "Biba" - end -end diff --git a/test/functions/core_test.rb b/test/functions/core_test.rb deleted file mode 100644 index c8b64ba..0000000 --- a/test/functions/core_test.rb +++ /dev/null @@ -1,40 +0,0 @@ -# frozen_string_literal: true - -require "test_helper" - -class CoreTestFunction - include ActiveFunction::Functions::Core - - def index - nil - end -end - -class CoreTest < Minitest::Test - def setup - @function = CoreTestFunction.new - end - - def test_action_to_be_called - mock = Minitest::Mock.new - mock.expect(:call, nil) - - @function.stub(:index, mock) do - @function.dispatch(:index, {body: {}}, committed_response) - end - - mock.verify - end - - def test_dispatch_raises_error_if_route_is_not_defined - assert_raises ActiveFunction::MissingRouteMethod do - @function.dispatch(:show, {}, response) - end - end - - def test_dispatch_raises_error_if_render_was_not_called - assert_raises ActiveFunction::NotRenderedError do - @function.dispatch(:index, {}, response) - end - end -end diff --git a/test/functions/rendering_test.rb b/test/functions/rendering_test.rb deleted file mode 100644 index 6430f9f..0000000 --- a/test/functions/rendering_test.rb +++ /dev/null @@ -1,90 +0,0 @@ -# frozen_string_literal: true - -require "test_helper" - -class RenderingTestFunction - include ActiveFunction::Functions::Core - include ActiveFunction::Functions::Rendering - - def index - render - end -end - -class RenderingTest < Minitest::Test - def setup - @function = RenderingTestFunction.new - end - - def test_render_default_response - @function.dispatch(:index, {}, response) - - response = @function.instance_variable_get(:@response) - - assert_equal response.status, 200 - assert_equal response.headers, {"Content-Type" => "application/json"} - assert_equal response.body, "{}" - end -end - -class DoubleRenderTestFunction < RenderingTestFunction - def index - super - render - end -end - -class DoubleRenderTest < Minitest::Test - def setup - @function = DoubleRenderTestFunction.new - end - - def test_double_render - assert_raises ActiveFunction::DoubleRenderError do - @function.dispatch(:index, {}, response) - end - end -end - -class RenderCustomResponseTestFunction < RenderingTestFunction - def index - render json: {a: 1, b: 2}, head: {"X-Test" => "test"}, status: 201 - end -end - -class RenderCustomResponseTest < Minitest::Test - def setup - @function = RenderCustomResponseTestFunction.new - end - - def test_render_custom_response - @function.dispatch(:index, {}, response) - - response = @function.instance_variable_get(:@response) - - assert_equal response.status, 201 - assert_equal response.headers, {"Content-Type" => "application/json", "X-Test" => "test"} - assert_equal response.body, '{"a":1,"b":2}' - end -end - -class NotRenderedTestFunction - include ActiveFunction::Functions::Core - include ActiveFunction::Functions::Rendering - - def index - nil - end -end - -class NotRenderedTest < Minitest::Test - def setup - @function = NotRenderedTestFunction.new - end - - def test_not_rendered - assert_raises ActiveFunction::NotRenderedError do - @function.dispatch(:index, {}, response) - end - end -end diff --git a/test/functions/response_test.rb b/test/functions/response_test.rb deleted file mode 100644 index 05fc7c4..0000000 --- a/test/functions/response_test.rb +++ /dev/null @@ -1,43 +0,0 @@ -# frozen_string_literal: true - -require "test_helper" - -class ResponseTest < Minitest::Test - def setup - @response = ActiveFunction::Functions::Response.new - end - - def test_status - @response.status = 201 - - assert_equal @response.status, 201 - end - - def test_headers - @response.headers = {"X-Test" => "test"} - - assert_equal @response.headers, {"X-Test" => "test"} - end - - def test_body - @response.body = "test" - - assert_equal @response.body, "test" - end - - def test_to_h - @response.status = 201 - @response.headers = {"X-Test" => "test"} - @response.body = "test" - - assert_equal @response.to_h, {statusCode: 201, headers: {"X-Test" => "test"}, body: "test"} - end - - def test_commit! - assert_equal @response.committed?, false - - @response.commit! - - assert_equal @response.committed?, true - end -end diff --git a/test/functions/strong_parameters_test.rb b/test/functions/strong_parameters_test.rb deleted file mode 100644 index a0f563d..0000000 --- a/test/functions/strong_parameters_test.rb +++ /dev/null @@ -1,200 +0,0 @@ -# frozen_string_literal: true - -require "test_helper" - -class StrongParametersFunction - include ActiveFunction::Functions::Core - include ActiveFunction::Functions::StrongParameters -end - -class StrongParametersTest < Minitest::Test - def setup - @function = StrongParametersFunction.new - end - - def test_params - assert_instance_of ActiveFunction::Functions::StrongParameters::Parameters, @function.params - end -end - -describe ActiveFunction::Functions::StrongParameters::Parameters do - let(:described_class) { ::ActiveFunction::Functions::StrongParameters::Parameters } - - def assert_nested_params(expected, actual) - assert_equal expected, actual.instance_variable_get(:@parameters) - end - - describe "#[]" do - it "returns the value of the parameter when it exists" do - params = described_class.new({name: "Pupa"}) - - assert_equal "Pupa", params[:name] - end - - it "returns Parameter instance if the parameter is a hash" do - params = described_class.new({user: {name: "Pupa"}}) - nested_params = params[:user] - - assert_instance_of described_class, nested_params - end - - it "returns array of Parameter instances if the parameter is an array of hashes" do - params = described_class.new({users: [{name: "Pupa"}, {name: "Lupa"}]}) - nested_params = params[:users] - - assert_instance_of Array, nested_params - assert_instance_of described_class, nested_params[0] - assert_instance_of described_class, nested_params[1] - end - - it "returns the value of the nested parameter when it exists" do - params = described_class.new({user: {name: "Pupa"}}) - - assert_nested_params({name: "Pupa"}, params[:user]) - end - - it "returns nested parameters when they exist" do - params = described_class.new({user: {name: "Pupa"}}) - nested_params = params[:user][:name] - - assert_equal "Pupa", nested_params - end - - it "returns nil when the parameter does not exist" do - params = described_class.new({}) - - assert_nil params[:name] - end - - it "returns nil when the nested parameter does not exist" do - params = described_class.new({user: {}}) - - assert_nil params[:user][:name] - end - end - - describe "#require" do - it "returns the value of the parameter when it exists" do - params = described_class.new({name: "Pupa"}) - - assert_equal "Pupa", params.require(:name) - end - - it "returns Parameter instance if the parameter is a hash" do - params = described_class.new({user: {name: "Pupa"}}) - required_params = params.require(:user) - - assert_instance_of described_class, required_params - end - - it "returns array of Parameter instances if the parameter is an array of hashes" do - params = described_class.new({users: [{name: "Pupa"}, {name: "Lupa"}]}) - required_params = params.require(:users) - - assert_instance_of Array, required_params - assert_instance_of described_class, required_params[0] - assert_instance_of described_class, required_params[1] - end - - it "returns the value of the nested parameter when it exists" do - params = described_class.new({user: {name: "Pupa"}}) - - assert_nested_params({name: "Pupa"}, params.require(:user)) - end - - it "returns nested parameters when they exist" do - params = described_class.new({user: {name: "Pupa"}}) - required_params = params.require(:user).require(:name) - - assert_equal "Pupa", required_params - end - - it "raises a ParameterMissingError when the parameter does not exist" do - params = described_class.new({}) - - assert_raises(ActiveFunction::ParameterMissingError) { params.require(:name) } - end - end - - describe "#permit" do - it "returns new Parameters instance with permitted parameters" do - params = described_class.new({id: 1, name: "Pupa"}) - permitted_params = params.permit(:id, :name) - - assert_instance_of described_class, permitted_params - assert_equal true, permitted_params.instance_variable_get(:@permitted) - assert_nested_params({id: 1, name: "Pupa"}, permitted_params) - end - - it "returns new Parameters instances with permitted nested parameters" do - params = described_class.new({user: {name: "Pupa", roles: [{id: 1, name: "Admin"}]}}) - permitted_params = params.permit(user: [:name, roles: [:id, :name]]) - - assert_instance_of described_class, permitted_params - assert_instance_of described_class, permitted_params[:user] - assert_instance_of described_class, permitted_params[:user][:roles][0] - - assert_equal true, permitted_params.instance_variable_get(:@permitted) - assert_equal true, permitted_params[:user].instance_variable_get(:@permitted) - assert_equal true, permitted_params[:user][:roles][0].instance_variable_get(:@permitted) - end - - it "returns new Parameters instance with valid values in nested parameters" do - params = described_class.new({user: {name: "Pupa", roles: [{id: 1, name: "Admin"}]}}) - permitted_params = params.permit(user: [:name, roles: [:id, :name]]) - - assert_equal "Pupa", permitted_params[:user][:name] - assert_nested_params({id: 1, name: "Admin"}, permitted_params[:user][:roles][0]) - end - - it "ignores parameter when the it does not exist" do - params = described_class.new({}) - - assert_nested_params({}, params.permit(:name)) - end - - it "ignores nested parameter when the it does not exist" do - params = described_class.new({user: {}}) - permitted_params = params.permit(user: [:name]) - - assert_nested_params({}, permitted_params[:user]) - end - end - - describe "#to_h" do - it "returns hash with permitted parameters" do - params = described_class.new({id: 1, name: "Pupa"}) - permitted_params = params.permit(:id, :name) - - assert_equal({id: 1, name: "Pupa"}, permitted_params.to_h) - end - - it "returns hash with permitted nested parameters" do - params = described_class.new({user: {name: "Pupa", roles: [{name: "Admin"}]}}) - permitted_params = params.permit(user: [:name, roles: [:id, :name]]) - - assert_equal({user: {name: "Pupa", roles: [{name: "Admin"}]}}, permitted_params.to_h) - end - - it "returns hash with permitted nested parameters when the parameter is an array of hashes" do - params = described_class.new({users: [{id: 1, name: "Pupa"}, {id:2, name: "Lupa"}]}) - permitted_params = params.permit(users: [:name]) - - assert_equal({users: [{name: "Pupa"}, {name: "Lupa"}]}, permitted_params.to_h) - end - - it "returns hash with permitted nested parameters when the parameter is an array of hashes with nested parameters" do - params = described_class.new({users: [{name: "Pupa", roles: [{id: 1, name: "Admin"}]}, {name: "Lupa", roles: [{id: 2, name: "User"}]}]}) - permitted_params = params.permit(users: [:name, roles: [:name]]) - - assert_equal({users: [{name: "Pupa", roles: [{name: "Admin"}]}, {name: "Lupa", roles: [{name: "User"}]}]}, permitted_params.to_h) - end - - # test UnpermittedParameterError case when the parameter is an array of hashes with nested parameters - it "raises UnpermittedParameterError when some parameter is not permitted" do - params = described_class.new({name: "Pupa"}) - - assert_raises(ActiveFunction::UnpermittedParameterError) { params.to_h } - end - end -end diff --git a/test/support/active_function_helper.rb b/test/support/active_function_helper.rb deleted file mode 100644 index b706d8f..0000000 --- a/test/support/active_function_helper.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -module ActiveFunctionHelper - def response - ActiveFunction::Functions::Response.new - end - - def committed_response - response.tap(&:commit!) - end -end - -Minitest::Test.include ActiveFunctionHelper From f2e349b8b7c792b75546acdba106ceb08337ee48 Mon Sep 17 00:00:00 2001 From: Nerbyk Date: Sun, 20 Aug 2023 12:07:36 +0700 Subject: [PATCH 2/8] Introduce Controller gem --- .../.github/workflows/CI.yml | 44 ++++ .../.github/workflows/lint.yml | 41 ++++ gems/activefunction-controller/.gitignore | 16 ++ gems/activefunction-controller/.rbnextrc | 5 + gems/activefunction-controller/.rubocop.yml | 42 ++++ gems/activefunction-controller/CHANGELOG.md | 43 ++++ .../CODE_OF_CONDUCT.md | 84 ++++++++ gems/activefunction-controller/Gemfile | 14 ++ gems/activefunction-controller/README.md | 154 ++++++++++++++ gems/activefunction-controller/Rakefile | 41 ++++ gems/activefunction-controller/Steepfile | 21 ++ .../active_function_controller.gemspec | 44 ++++ gems/activefunction-controller/bin/console | 15 ++ gems/activefunction-controller/bin/rubocop | 27 +++ gems/activefunction-controller/bin/setup | 8 + .../gemfiles/rbs.gemfile | 4 + .../gemfiles/rubocop.gemfile | 8 + .../strong_parameters.rb | 102 +++++++++ .../3.0/active_function_controller/core.rb | 47 ++++ .../active_function_controller/response.rb | 28 +++ .../lib/active_function_controller.rb | 26 +++ .../active_function_controller/callbacks.rb | 67 ++++++ .../lib/active_function_controller/core.rb | 47 ++++ .../active_function_controller/rendering.rb | 29 +++ .../active_function_controller/response.rb | 28 +++ .../strong_parameters.rb | 102 +++++++++ .../lib/active_function_controller/version.rb | 7 + .../sig/active_function_controller.rbs | 19 ++ .../active_function_controller/callbacks.rbs | 40 ++++ .../sig/active_function_controller/core.rbs | 33 +++ .../active_function_controller/rendering.rbs | 18 ++ .../active_function_controller/response.rbs | 18 ++ .../strong_parameters.rbs | 46 ++++ .../sig/manifest.yml | 3 + .../activefunction-controller/sig/typeprof.rb | 21 ++ .../test/active_function_test.rb | 73 +++++++ .../fixtures/aws_events/api_gateway_http.json | 101 +++++++++ .../test/fixtures/aws_events/dynamodb.json | 64 ++++++ .../test/functions/callbacks_test.rb | 171 +++++++++++++++ .../test/functions/core_test.rb | 40 ++++ .../test/functions/rendering_test.rb | 90 ++++++++ .../test/functions/response_test.rb | 43 ++++ .../test/functions/strong_parameters_test.rb | 200 ++++++++++++++++++ .../test/support/active_function_helper.rb | 13 ++ .../test/test_helper.rb | 13 ++ 45 files changed, 2100 insertions(+) create mode 100644 gems/activefunction-controller/.github/workflows/CI.yml create mode 100644 gems/activefunction-controller/.github/workflows/lint.yml create mode 100644 gems/activefunction-controller/.gitignore create mode 100644 gems/activefunction-controller/.rbnextrc create mode 100644 gems/activefunction-controller/.rubocop.yml create mode 100644 gems/activefunction-controller/CHANGELOG.md create mode 100644 gems/activefunction-controller/CODE_OF_CONDUCT.md create mode 100644 gems/activefunction-controller/Gemfile create mode 100644 gems/activefunction-controller/README.md create mode 100644 gems/activefunction-controller/Rakefile create mode 100644 gems/activefunction-controller/Steepfile create mode 100644 gems/activefunction-controller/active_function_controller.gemspec create mode 100755 gems/activefunction-controller/bin/console create mode 100755 gems/activefunction-controller/bin/rubocop create mode 100755 gems/activefunction-controller/bin/setup create mode 100644 gems/activefunction-controller/gemfiles/rbs.gemfile create mode 100644 gems/activefunction-controller/gemfiles/rubocop.gemfile create mode 100644 gems/activefunction-controller/lib/.rbnext/2.7/active_function_controller/strong_parameters.rb create mode 100644 gems/activefunction-controller/lib/.rbnext/3.0/active_function_controller/core.rb create mode 100644 gems/activefunction-controller/lib/.rbnext/3.0/active_function_controller/response.rb create mode 100644 gems/activefunction-controller/lib/active_function_controller.rb create mode 100644 gems/activefunction-controller/lib/active_function_controller/callbacks.rb create mode 100644 gems/activefunction-controller/lib/active_function_controller/core.rb create mode 100644 gems/activefunction-controller/lib/active_function_controller/rendering.rb create mode 100644 gems/activefunction-controller/lib/active_function_controller/response.rb create mode 100644 gems/activefunction-controller/lib/active_function_controller/strong_parameters.rb create mode 100644 gems/activefunction-controller/lib/active_function_controller/version.rb create mode 100644 gems/activefunction-controller/sig/active_function_controller.rbs create mode 100644 gems/activefunction-controller/sig/active_function_controller/callbacks.rbs create mode 100644 gems/activefunction-controller/sig/active_function_controller/core.rbs create mode 100644 gems/activefunction-controller/sig/active_function_controller/rendering.rbs create mode 100644 gems/activefunction-controller/sig/active_function_controller/response.rbs create mode 100644 gems/activefunction-controller/sig/active_function_controller/strong_parameters.rbs create mode 100644 gems/activefunction-controller/sig/manifest.yml create mode 100644 gems/activefunction-controller/sig/typeprof.rb create mode 100644 gems/activefunction-controller/test/active_function_test.rb create mode 100644 gems/activefunction-controller/test/fixtures/aws_events/api_gateway_http.json create mode 100644 gems/activefunction-controller/test/fixtures/aws_events/dynamodb.json create mode 100644 gems/activefunction-controller/test/functions/callbacks_test.rb create mode 100644 gems/activefunction-controller/test/functions/core_test.rb create mode 100644 gems/activefunction-controller/test/functions/rendering_test.rb create mode 100644 gems/activefunction-controller/test/functions/response_test.rb create mode 100644 gems/activefunction-controller/test/functions/strong_parameters_test.rb create mode 100644 gems/activefunction-controller/test/support/active_function_helper.rb create mode 100644 gems/activefunction-controller/test/test_helper.rb diff --git a/gems/activefunction-controller/.github/workflows/CI.yml b/gems/activefunction-controller/.github/workflows/CI.yml new file mode 100644 index 0000000..59d4530 --- /dev/null +++ b/gems/activefunction-controller/.github/workflows/CI.yml @@ -0,0 +1,44 @@ +name: CI Build + +on: + push: + branches: [ master ] + pull_request: + branches: [ '**' ] + +jobs: + minitest: + runs-on: ubuntu-latest + env: + BUNDLE_JOBS: 4 + BUNDLE_RETRY: 3 + BUNDLE_GEMFILE: "${{ matrix.gemfile }}" + CI: true + strategy: + fail-fast: false + matrix: + ruby: ["3.0"] + gemfile: [ + "Gemfile" + ] + rbs: [ 'false' ] + include: + - ruby: "3.1" + rbs: 'true' + gemfile: "Gemfile" + - ruby: "2.7" + rbs: 'false' + gemfile: "Gemfile" + steps: + - uses: actions/checkout@v2 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + bundler: 2.2.15 + - name: Run Ruby Next + run: bundle exec rake nextify + - name: Run MiniTest + run: bundle exec rake test + + diff --git a/gems/activefunction-controller/.github/workflows/lint.yml b/gems/activefunction-controller/.github/workflows/lint.yml new file mode 100644 index 0000000..fb5e383 --- /dev/null +++ b/gems/activefunction-controller/.github/workflows/lint.yml @@ -0,0 +1,41 @@ +name: Rubocop & Steep + +on: + push: + branches: + - master + pull_request: + +jobs: + rubocop: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: 2.7 + - name: Lint Ruby code with RuboCop + run: | + gem install bundler + bundle install --gemfile gemfiles/rubocop.gemfile --jobs 4 --retry 3 + bundle exec --gemfile gemfiles/rubocop.gemfile rubocop + steep: + runs-on: ubuntu-latest + env: + BUNDLE_JOBS: 4 + BUNDLE_RETRY: 3 + BUNDLE_FORCE_RUBY_PLATFORM: 1 + CI: true + strategy: + matrix: + ruby: ["3.0"] + steps: + - uses: actions/checkout@v2 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + bundler: 2.2.15 + - name: Run Steep + run: | + bundle exec rake steep \ No newline at end of file diff --git a/gems/activefunction-controller/.gitignore b/gems/activefunction-controller/.gitignore new file mode 100644 index 0000000..fde9bf6 --- /dev/null +++ b/gems/activefunction-controller/.gitignore @@ -0,0 +1,16 @@ +/.bundle/ +/.yardoc +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/spec/reports/ +/tmp/ + +gemfiles/*.lock + +Gemfile.lock +Gemfile.local +.rspec +.ruby-version +*.gem diff --git a/gems/activefunction-controller/.rbnextrc b/gems/activefunction-controller/.rbnextrc new file mode 100644 index 0000000..834894a --- /dev/null +++ b/gems/activefunction-controller/.rbnextrc @@ -0,0 +1,5 @@ +nextify: | + ./lib + --min-version=2.5 + --edge + --proposed diff --git a/gems/activefunction-controller/.rubocop.yml b/gems/activefunction-controller/.rubocop.yml new file mode 100644 index 0000000..644bc11 --- /dev/null +++ b/gems/activefunction-controller/.rubocop.yml @@ -0,0 +1,42 @@ +require: + - standard/cop/block_single_line_braces + - ruby-next/rubocop + +inherit_gem: + standard: config/base.yml + +AllCops: + Exclude: + - 'bin/*' + - 'tmp/**/*' + - 'Gemfile' + - 'vendor/**/*' + - 'gemfiles/**/*' + - '*.gemspec' + DisplayCopNames: true + SuggestExtensions: false + TargetRubyVersion: next + +Standard/BlockSingleLineBraces: + Enabled: false + +Style/FrozenStringLiteralComment: + Enabled: true + +Style/HashConversion: + Enabled: false + +Naming/FileName: + Exclude: + - '**/*.md' + +# FIXME: Enable back when Ruby Next 0.14 is released +Layout/SpaceAfterColon: + Enabled: false + +Layout/ExtraSpacing: + ForceEqualSignAlignment: true + +Layout/HashAlignment: + EnforcedHashRocketStyle: table + EnforcedColonStyle: table diff --git a/gems/activefunction-controller/CHANGELOG.md b/gems/activefunction-controller/CHANGELOG.md new file mode 100644 index 0000000..5074aef --- /dev/null +++ b/gems/activefunction-controller/CHANGELOG.md @@ -0,0 +1,43 @@ +## [Unreleased] + +## [0.1.0] - 2022-12-28 + +- Add `before_action` and `after_action` callbacks with `:only` and `:if` options +- Add `ActiveFunction::Controller::Base#params` with `require`, `permit`, `[]` and `to_h` public methods +- Add specs for `ActiveFunction::Controller::Base.params` module +- Add `ActiveFunction::Controller::Base#render` with `:status`, `:json` and `:head` options +- Add RBS signature +- Add RBS Aws Event Types +- Add public interface type `steep` checking +- Add `ruby-next` transpiler + +## [0.2.0] - 2023-01-08 + +- Add unit tests +- Fix Steep pipeline & add better RBS type signatures +- Refactor `::Functions` module +- Add `Response` class + +## [0.3.0] - 2023-01-12 + +- cleanup +- add ActiveFunction::Controller::Response#commit! +- extract action processing to separate method to handle ActiveFunction::Controller::Callbacks#process overriding +- add test for ActiveFunction::Controller::Base.process + + +# [0.3.1] - 2023-02-09 + +- Updated readme +- Make callbacks inheritable +- `include` -> `prepend` Core module + +# [0.3.2] - 2023-02-10 + +- Finish readme +- Fix callbacks broken by `prepend` change +- Add more tests for `#process` public interface + +# [0.3.4] - 2023-05-02 + +- Fix RubyNext runtime integration diff --git a/gems/activefunction-controller/CODE_OF_CONDUCT.md b/gems/activefunction-controller/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..c7280d2 --- /dev/null +++ b/gems/activefunction-controller/CODE_OF_CONDUCT.md @@ -0,0 +1,84 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at danil.maximov@flatstack.com. All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of actions. + +**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, +available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. diff --git a/gems/activefunction-controller/Gemfile b/gems/activefunction-controller/Gemfile new file mode 100644 index 0000000..198133c --- /dev/null +++ b/gems/activefunction-controller/Gemfile @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +gem 'pry-byebug', platform: :mri + +gemspec + +eval_gemfile "gemfiles/rubocop.gemfile" +eval_gemfile "gemfiles/rbs.gemfile" + +local_gemfile = "#{File.dirname(__FILE__)}/Gemfile.local" + +eval(File.read(local_gemfile)) if File.exist?(local_gemfile) # rubocop:disable Security/Eval diff --git a/gems/activefunction-controller/README.md b/gems/activefunction-controller/README.md new file mode 100644 index 0000000..66652bd --- /dev/null +++ b/gems/activefunction-controller/README.md @@ -0,0 +1,154 @@ +# ActiveFunction + +rails/action_controller like gem which provides lightweight callbacks, strong parameters & rendering features. It's designed to be used with AWS Lambda functions, but can be also used with any Ruby application. + +Implemented with some of ruby 3.x features, but also supports ruby 2.6.x thanks to [RubyNext](https://github.com/ruby-next/ruby-next) transpiler. Type safety achieved by RBS and [Steep](https://github.com/soutaro/steep). + + +## A Short Example + +Here's a simple example of a controller that uses ActiveFunction::Controller: + +```ruby +require 'active-function-controller' + +class AppFunction < ActiveFunction::Controller::Base + def index + render json: SomeTable.all + end +end +``` + +Use `#process` method to proceed the request: + +```ruby +AppFunction.process(:index) # processes index action of AppFunction instance +``` +Also check extended [example](https://github.com/DanilMaximov/activefunction/tree/master/active_function_example) +## Callbacks +ActiveFunction supports simple callbacks `:before` and `:after` which runs around provided action in `#process`. + +```ruby +class AppFunction < ActiveFunction::Controller::Base + before_action :set_user + after_action :log_response + + # some action ... + + private + + def set_user + @user = User.first + end + + def log_response + Logger.info @response + end +end +``` + +Callbacks also can be user with `only: Array[Symbol]` and `if: Symbol` options. + +```ruby +class AppFunction < ActiveFunction::Controller::Base + before_action :set_user, only: %i[show update destroy], if: :request_valid? + + # some actions ... + + private def request_valid? = true +end +``` + +Callbacks are inheritable so all callbacks calls will be inherited from base class +```ruby +class BaseFunction < ActiveFunction::Controller::Base + before_action :set_current_user + + def set_current_user + @current_user = User.first + end +end + +class PostsFunction < BaseFunction + def index + render json: @current_user + end +end +``` +## Strong Parameters +ActiveFunction supports strong parameters which can be accessed by `#params` instance method. Strong parameters hash can be passed in `#process` as second argument. + +```ruby +PostFunction.process(:index, data: { id: 1, name: "Pupa" }) +``` + +Simple usage: +```ruby +class PostsFunction < ActiveFunction::Controller::Base + def index + render json: permitted_params + end + + def permitted_params = params + .require(:data) + .permit(:id, :name) + .to_h +end +``` +Strong params supports nested attributes +```ruby +params.permit(:id, :name, :address => [:city, :street]) +``` + +## Rendering +ActiveFunction::Controller supports rendering of JSON. Rendering is obligatory for any function naction and can be done by `#render` method. +```ruby +class PostsFunction < ActiveFunction::Controller::Base + def index + render json: { id: 1, name: "Pupa" } + end +end +``` +default status code is 200, but it can be changed by `:status` option +```ruby +class PostsFunction < ActiveFunction::Controller::Base + def index + render json: { id: 1, name: "Pupa" }, status: 201 + end +end +``` +Headers can be passed by `:headers` option. Default headers are `{"Content-Type" => "application/json"}`. +```ruby +class PostsFunction < ActiveFunction::Controller::Base + def index + render json: { id: 1, name: "Pupa" }, headers: { "X-Request-Id" => "123" } + end +end +``` + + +## Installation + +Add this line to your application's Gemfile: + +```ruby +gem 'activefunction', git: "https://github.com/DanilMaximov/activefunction.git" +``` + +## Development + +After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/rake test` to run the tests and `bin/rake steep` to run type checker. + +To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org). + +## Contributing + +Bug reports and pull requests are welcome on GitHub at https://github.com/DanilMaximov/activefunction. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/DanilMaximov/activefunction/blob/master/CODE_OF_CONDUCT.md). + +## License + +The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). + +## Code of Conduct + +Everyone interacting in the ActiveFunction::Controller project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/DanilMaximov/activefunction/blob/master/CODE_OF_CONDUCT.md). diff --git a/gems/activefunction-controller/Rakefile b/gems/activefunction-controller/Rakefile new file mode 100644 index 0000000..07a3ea0 --- /dev/null +++ b/gems/activefunction-controller/Rakefile @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require "bundler/gem_tasks" +require "rake/testtask" + +Rake::TestTask.new do |t| + t.libs << "test" + t.libs << "lib" + t.test_files = FileList["test/**/*_test.rb"] + t.warning = false + t.verbose = true +end + +begin + require "rubocop/rake_task" + RuboCop::RakeTask.new +rescue LoadError + task(:rubocop) {} +end + +RuboCop::RakeTask.new + +task :steep do + require "steep" + require "steep/cli" + + Steep::CLI.new(argv: ["check"], stdout: $stdout, stderr: $stderr, stdin: $stdin).run +end + +namespace :steep do + task :stats do + exec "bundle exec steep stats --log-level=fatal --format=table'" + end +end + +desc "Run Ruby Next nextify" +task :nextify do + sh "bundle exec ruby-next nextify -V" +end + +task default: %i[test rubocop steep] diff --git a/gems/activefunction-controller/Steepfile b/gems/activefunction-controller/Steepfile new file mode 100644 index 0000000..b47ae5c --- /dev/null +++ b/gems/activefunction-controller/Steepfile @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +target :lib do + signature "sig" + + check "lib" + + ignore "lib/active_function_controller/version.rb" + # Temporary disable type checking for this file due to: + # lib/active_function/functions/strong_parameters.rb:94:44: [error] Unsupported splat node occurrence + # │ Diagnostic ID: Ruby::UnsupportedSyntax + # │ + # └ attribute.map { _1.send(method, *options.to_a) } + # ~~~~~~~~~~~~~ + ignore "lib/active_function_controller/strong_parameters.rb" + + library( + "json", + "forwardable" + ) +end diff --git a/gems/activefunction-controller/active_function_controller.gemspec b/gems/activefunction-controller/active_function_controller.gemspec new file mode 100644 index 0000000..98e4680 --- /dev/null +++ b/gems/activefunction-controller/active_function_controller.gemspec @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require_relative "lib/active_function_controller/version" + +Gem::Specification.new do |spec| + spec.name = "active-function-controller" + spec.version = ActiveFunction::Controller::VERSION + spec.authors = ["Nerbyk"] + spec.email = ["danil.maximov2000@gmail.com"] + + spec.summary = %( + lightweight rails/action_controller clone which provides + callbacks, strong parameters & rendering features. + ) + spec.description = %( + lightweight rails/action_controller clone which provides lightweight callbacks, + strong parameters & rendering features. It's designed to be used with + AWS Lambda functions, but can be also used with any Ruby application. + + Implemented with some of ruby 3.x features, but also supports + ruby 2.6.x thanks to RubyNext transpiler. Type safety achieved + by RBS and Steep. + ) + spec.homepage = "https://github.com/DanilMaximov/acitvefunction" + spec.license = "MIT" + spec.metadata = { + "homepage_uri" => "https://github.com/DanilMaximov/activefunction/gems/active-function-controller", + "source_code_uri" => "https://github.com/DanilMaximov/activefunction/gems/active-function-controller", + "changelog_uri" => "https://github.com/DanilMaximov/activefunction/gems/active-function-controller/CHANGELOG.md" + } + + spec.files = Dir.glob("lib/**/*") + Dir.glob("lib/.rbnext/**/*") + Dir.glob("bin/**/*") + %w[sig/active_function_controller.rbs sig/manifest.yml] + %w[README.md LICENSE.txt CHANGELOG.md] + + spec.require_paths = ["lib"] + + spec.required_ruby_version = ">= 2.6" + + spec.add_runtime_dependency "ruby-next-core", ">= 0.14.0" + + spec.add_development_dependency "ruby-next", ">= 0.14.0" + spec.add_development_dependency "rake", ">= 13.0" + spec.add_development_dependency "minitest", "~> 5.15.0" + spec.add_development_dependency "minitest-reporters", "~> 1.4.3" +end diff --git a/gems/activefunction-controller/bin/console b/gems/activefunction-controller/bin/console new file mode 100755 index 0000000..e7821b8 --- /dev/null +++ b/gems/activefunction-controller/bin/console @@ -0,0 +1,15 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "bundler/setup" +require "activefunction/controller" + +# You can add fixtures and/or initialization code here to make experimenting +# with your gem easier. You can also use a different console, if you like. + +# (If you use this, don't forget to add pry to your Gemfile!) +# require "pry" +# Pry.start + +require "irb" +IRB.start(__FILE__) diff --git a/gems/activefunction-controller/bin/rubocop b/gems/activefunction-controller/bin/rubocop new file mode 100755 index 0000000..369a05b --- /dev/null +++ b/gems/activefunction-controller/bin/rubocop @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'rubocop' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("rubocop", "rubocop") diff --git a/gems/activefunction-controller/bin/setup b/gems/activefunction-controller/bin/setup new file mode 100755 index 0000000..dce67d8 --- /dev/null +++ b/gems/activefunction-controller/bin/setup @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' +set -vx + +bundle install + +# Do any other automated setup that you need to do here diff --git a/gems/activefunction-controller/gemfiles/rbs.gemfile b/gems/activefunction-controller/gemfiles/rbs.gemfile new file mode 100644 index 0000000..163251f --- /dev/null +++ b/gems/activefunction-controller/gemfiles/rbs.gemfile @@ -0,0 +1,4 @@ +source "https://rubygems.org" do + gem "rbs" + gem "steep", "~> 1.2" +end diff --git a/gems/activefunction-controller/gemfiles/rubocop.gemfile b/gems/activefunction-controller/gemfiles/rubocop.gemfile new file mode 100644 index 0000000..0bcb769 --- /dev/null +++ b/gems/activefunction-controller/gemfiles/rubocop.gemfile @@ -0,0 +1,8 @@ +source "https://rubygems.org" do + gem "rubocop", "~> 1.29.0" + gem "rubocop-performance" + gem "rubocop-rake" + gem "rubocop-shopify" + gem "standard", "~> 1.12.1" + gem "ruby-next", ">= 0.12" +end diff --git a/gems/activefunction-controller/lib/.rbnext/2.7/active_function_controller/strong_parameters.rb b/gems/activefunction-controller/lib/.rbnext/2.7/active_function_controller/strong_parameters.rb new file mode 100644 index 0000000..19443a4 --- /dev/null +++ b/gems/activefunction-controller/lib/.rbnext/2.7/active_function_controller/strong_parameters.rb @@ -0,0 +1,102 @@ +# frozen_string_literal: true + +require "forwardable" + +module ActiveFunction::Controller + class ParameterMissingError < Error + MESSAGE_TEMPLATE = "Missing parameter: %s" + + attr_reader :message + + def initialize(param) + MESSAGE_TEMPLATE % param + end + end + + class UnpermittedParameterError < Error + MESSAGE_TEMPLATE = "Unpermitted parameter: %s" + + attr_reader :message + + def initialize(param) + MESSAGE_TEMPLATE % param + end + end + + module StrongParameters + def params + @_params ||= Parameters.new(@request) + end + + class Parameters + extend Forwardable + def_delegators :@parameters, :each, :map + include Enumerable + + def initialize(parameters, permitted: false) + @parameters = parameters + @permitted = permitted + end + + def [](attribute) + nested_attribute(parameters[attribute]) + end + + def require(attribute) + value = self[attribute] + + raise ParameterMissingError, attribute if value.nil? + + value + end + + def permit(*attributes) + pparams = {} + + attributes.each do |attribute| + if attribute.is_a? Hash + attribute.each do |k, v| + pparams[k] = process_nested(self[k], :permit, v) + end + else + next unless parameters.key?(attribute) + + pparams[attribute] = self[attribute] + end + end + + Parameters.new(pparams, permitted: true) + end + + def to_h + raise UnpermittedParameterError, parameters.keys unless @permitted + + parameters.transform_values { |_1| process_nested(_1, :to_h) } + end + + private + + def nested_attribute(attribute) + if attribute.is_a? Hash + Parameters.new(attribute) + elsif attribute.is_a?(Array) && attribute[0].is_a?(Hash) + attribute.map { |_1| Parameters.new(_1) } + else + attribute + end + end + + def process_nested(attribute, method, options = []) + if attribute.is_a? Parameters + attribute.send(method, *options) + elsif attribute.is_a?(Array) && attribute[0].is_a?(Parameters) + attribute.map { |_1| _1.send(method, *options) } + else + attribute + end + end + + attr_reader :parameters + end + end +end diff --git a/gems/activefunction-controller/lib/.rbnext/3.0/active_function_controller/core.rb b/gems/activefunction-controller/lib/.rbnext/3.0/active_function_controller/core.rb new file mode 100644 index 0000000..afb9402 --- /dev/null +++ b/gems/activefunction-controller/lib/.rbnext/3.0/active_function_controller/core.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module ActiveFunction::Controller + class MissingRouteMethod < Error + MESSAGE_TEMPLATE = "Missing function route: %s" + + attr_reader :message + + def initialize(context) + @message = MESSAGE_TEMPLATE % context + end + end + + class NotRenderedError < Error + MESSAGE_TEMPLATE = "render was not called: %s" + + attr_reader :message + + def initialize(context) + @message = MESSAGE_TEMPLATE % context + end + end + + module Core + attr_reader :action_name, :request, :response + + def dispatch(action_name, request, response) + @action_name = action_name + @request = request + @response = response + + raise MissingRouteMethod, @action_name unless respond_to?(action_name) + + process(@action_name) + + raise NotRenderedError, @action_name unless performed? + + @response.to_h + end + + private + + def process(action) ; public_send(action); end + + def performed? ; @response.committed?; end + end +end diff --git a/gems/activefunction-controller/lib/.rbnext/3.0/active_function_controller/response.rb b/gems/activefunction-controller/lib/.rbnext/3.0/active_function_controller/response.rb new file mode 100644 index 0000000..17e164a --- /dev/null +++ b/gems/activefunction-controller/lib/.rbnext/3.0/active_function_controller/response.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module ActiveFunction::Controller + class Response + attr_accessor :status, :headers, :body + + def initialize(status: 200, headers: {}, body: nil) + @status = status + @headers = headers + @body = body + @committed = false + end + + def to_h + { + statusCode: status, + headers: headers, + body: body + } + end + + def commit! + @committed = true + end + + def committed? ; @committed; end + end +end diff --git a/gems/activefunction-controller/lib/active_function_controller.rb b/gems/activefunction-controller/lib/active_function_controller.rb new file mode 100644 index 0000000..d900be7 --- /dev/null +++ b/gems/activefunction-controller/lib/active_function_controller.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require_relative "active_function_controller/version" + +module ActiveFunction + module Controller + class Error < StandardError; end + + class Base + require_relative "active_function_controller/core" + require_relative "active_function_controller/callbacks" + require_relative "active_function_controller/strong_parameters" + require_relative "active_function_controller/rendering" + require_relative "active_function_controller/response" + + include Core + include Callbacks + include Rendering + include StrongParameters + + def self.process(action_name, request = {}, response = Response.new) + new.dispatch(action_name, request, response) + end + end + end +end diff --git a/gems/activefunction-controller/lib/active_function_controller/callbacks.rb b/gems/activefunction-controller/lib/active_function_controller/callbacks.rb new file mode 100644 index 0000000..3eecdea --- /dev/null +++ b/gems/activefunction-controller/lib/active_function_controller/callbacks.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +module ActiveFunction::Controller + class MissingCallbackContext < Error + MESSAGE_TEMPLATE = "Missing callback context: %s" + + attr_reader :message + + def initialize(context) + @message = MESSAGE_TEMPLATE % context + end + end + + module Callbacks + def self.included(base) + base.extend(ClassMethods) + end + + private + + def process(*) + _run_callbacks :before + + super + + _run_callbacks :after + end + + def _run_callbacks(type) + self.class.callbacks[type].each do |callback_method, options| + raise MissingCallbackContext, callback_method unless respond_to?(callback_method, true) + + send(callback_method) if _executable?(options) + end + end + + def _executable?(options) + return false if options[:only] && !options[:only].include?(@action_name) + return false if options[:if] && !send(options[:if]) + true + end + + module ClassMethods + def inherited(subclass) + subclass.instance_variable_set(:@__callbacks, @__callbacks) + end + + def before_action(method, options = {}) + set_callback :before, method, options + end + + def after_action(method, options = {}) + set_callback :after, method, options + end + + def set_callback(type, method, options = {}) + callbacks[type][method] = options + end + + def callbacks + @__callbacks ||= {before: {}, after: {}} + + @__callbacks + end + end + end +end diff --git a/gems/activefunction-controller/lib/active_function_controller/core.rb b/gems/activefunction-controller/lib/active_function_controller/core.rb new file mode 100644 index 0000000..57c1719 --- /dev/null +++ b/gems/activefunction-controller/lib/active_function_controller/core.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module ActiveFunction::Controller + class MissingRouteMethod < Error + MESSAGE_TEMPLATE = "Missing function route: %s" + + attr_reader :message + + def initialize(context) + @message = MESSAGE_TEMPLATE % context + end + end + + class NotRenderedError < Error + MESSAGE_TEMPLATE = "render was not called: %s" + + attr_reader :message + + def initialize(context) + @message = MESSAGE_TEMPLATE % context + end + end + + module Core + attr_reader :action_name, :request, :response + + def dispatch(action_name, request, response) + @action_name = action_name + @request = request + @response = response + + raise MissingRouteMethod, @action_name unless respond_to?(action_name) + + process(@action_name) + + raise NotRenderedError, @action_name unless performed? + + @response.to_h + end + + private + + def process(action) = public_send(action) + + def performed? = @response.committed? + end +end diff --git a/gems/activefunction-controller/lib/active_function_controller/rendering.rb b/gems/activefunction-controller/lib/active_function_controller/rendering.rb new file mode 100644 index 0000000..ae22195 --- /dev/null +++ b/gems/activefunction-controller/lib/active_function_controller/rendering.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require "json" + +module ActiveFunction::Controller + class DoubleRenderError < Error + MESSAGE_TEMPLATE = "#render was called multiple times in action: %s" + + attr_reader :message + + def initialize(context) + @message = MESSAGE_TEMPLATE % context + end + end + + module Rendering + DEFAULT_HEADER = {"Content-Type" => "application/json"}.freeze + + def render(status: 200, json: {}, head: {}) + raise DoubleRenderError, @action_name if performed? + + @response.status = status + @response.headers = head.merge(Hash[DEFAULT_HEADER]) + @response.body = JSON.generate(json) + + @response.commit! + end + end +end diff --git a/gems/activefunction-controller/lib/active_function_controller/response.rb b/gems/activefunction-controller/lib/active_function_controller/response.rb new file mode 100644 index 0000000..c5ff701 --- /dev/null +++ b/gems/activefunction-controller/lib/active_function_controller/response.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module ActiveFunction::Controller + class Response + attr_accessor :status, :headers, :body + + def initialize(status: 200, headers: {}, body: nil) + @status = status + @headers = headers + @body = body + @committed = false + end + + def to_h + { + statusCode: status, + headers: headers, + body: body + } + end + + def commit! + @committed = true + end + + def committed? = @committed + end +end diff --git a/gems/activefunction-controller/lib/active_function_controller/strong_parameters.rb b/gems/activefunction-controller/lib/active_function_controller/strong_parameters.rb new file mode 100644 index 0000000..97364c5 --- /dev/null +++ b/gems/activefunction-controller/lib/active_function_controller/strong_parameters.rb @@ -0,0 +1,102 @@ +# frozen_string_literal: true + +require "forwardable" + +module ActiveFunction::Controller + class ParameterMissingError < Error + MESSAGE_TEMPLATE = "Missing parameter: %s" + + attr_reader :message + + def initialize(param) + MESSAGE_TEMPLATE % param + end + end + + class UnpermittedParameterError < Error + MESSAGE_TEMPLATE = "Unpermitted parameter: %s" + + attr_reader :message + + def initialize(param) + MESSAGE_TEMPLATE % param + end + end + + module StrongParameters + def params + @_params ||= Parameters.new(@request) + end + + class Parameters + extend Forwardable + def_delegators :@parameters, :each, :map + include Enumerable + + def initialize(parameters, permitted: false) + @parameters = parameters + @permitted = permitted + end + + def [](attribute) + nested_attribute(parameters[attribute]) + end + + def require(attribute) + value = self[attribute] + + raise ParameterMissingError, attribute if value.nil? + + value + end + + def permit(*attributes) + pparams = {} + + attributes.each do |attribute| + if attribute.is_a? Hash + attribute.each do |k, v| + pparams[k] = process_nested(self[k], :permit, v) + end + else + next unless parameters.key?(attribute) + + pparams[attribute] = self[attribute] + end + end + + Parameters.new(pparams, permitted: true) + end + + def to_h + raise UnpermittedParameterError, parameters.keys unless @permitted + + parameters.transform_values { process_nested(_1, :to_h) } + end + + private + + def nested_attribute(attribute) + if attribute.is_a? Hash + Parameters.new(attribute) + elsif attribute.is_a?(Array) && attribute[0].is_a?(Hash) + attribute.map { Parameters.new(_1) } + else + attribute + end + end + + def process_nested(attribute, method, options = []) + if attribute.is_a? Parameters + attribute.send(method, *options) + elsif attribute.is_a?(Array) && attribute[0].is_a?(Parameters) + attribute.map { _1.send(method, *options) } + else + attribute + end + end + + attr_reader :parameters + end + end +end diff --git a/gems/activefunction-controller/lib/active_function_controller/version.rb b/gems/activefunction-controller/lib/active_function_controller/version.rb new file mode 100644 index 0000000..d0a8c9f --- /dev/null +++ b/gems/activefunction-controller/lib/active_function_controller/version.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module ActiveFunction + module Controller + VERSION = "0.3.4" + end +end diff --git a/gems/activefunction-controller/sig/active_function_controller.rbs b/gems/activefunction-controller/sig/active_function_controller.rbs new file mode 100644 index 0000000..9f36002 --- /dev/null +++ b/gems/activefunction-controller/sig/active_function_controller.rbs @@ -0,0 +1,19 @@ +module ActiveFunction + module Controller + class Error < StandardError + end + + type hash = Hash[untyped, untyped] + + interface _Controller + def performed?: -> bool + end + + class Base + extend Controller::Callbacks::ClassMethods + + def self.new: -> Controller::Core + def self.process: (Symbol action_name, ?hash request, ?Controller::Response response) -> Controller::Response::responseHash + end + end +end diff --git a/gems/activefunction-controller/sig/active_function_controller/callbacks.rbs b/gems/activefunction-controller/sig/active_function_controller/callbacks.rbs new file mode 100644 index 0000000..24735c6 --- /dev/null +++ b/gems/activefunction-controller/sig/active_function_controller/callbacks.rbs @@ -0,0 +1,40 @@ +module ActiveFunction::Controller + class MissingCallbackContext < Error + MESSAGE_TEMPLATE: String + + attr_reader message: String + + def initialize: (untyped context) -> void + end + + module Callbacks : Base, Core + interface _Callbacks + def callbacks: () -> Hash[Symbol, hash] + end + + include _Controller + extend _Callbacks + + type callbackType = :before | :after + + def self.super: () -> singleton(Core) + def process: (*untyped) -> untyped + + private + + def _run_callbacks: (callbackType `type`) -> void + def _executable?: (hash options) -> bool + + module ClassMethods + include _Callbacks + @__callbacks: Hash[Symbol, hash] + + def before_action: (Symbol method, ?hash options) -> void + def after_action: (Symbol method, ?hash options) -> void + def set_callback: (callbackType type, Symbol method, ?hash options) -> void + def inherited: (singleton(Base) subclass) -> void + end + + def self.included: (singleton(Base) base) -> void + end +end diff --git a/gems/activefunction-controller/sig/active_function_controller/core.rbs b/gems/activefunction-controller/sig/active_function_controller/core.rbs new file mode 100644 index 0000000..ebede51 --- /dev/null +++ b/gems/activefunction-controller/sig/active_function_controller/core.rbs @@ -0,0 +1,33 @@ +module ActiveFunction::Controller + class MissingRouteMethod < Error + MESSAGE_TEMPLATE: String + + attr_reader message: String + + def initialize: (String context) -> void + end + + class NotRenderedError < Error + MESSAGE_TEMPLATE: String + + attr_reader message: String + + def initialize: (String context) -> void + end + + + module Core : Base + include _Controller + + @performed: bool + @action_name: Symbol + @request: Hash[Symbol, untyped] + @response: Response + + def dispatch: (Symbol action_name, hash request, Response response) -> Response::responseHash + + private + + def process: (Symbol action) -> void + end +end diff --git a/gems/activefunction-controller/sig/active_function_controller/rendering.rbs b/gems/activefunction-controller/sig/active_function_controller/rendering.rbs new file mode 100644 index 0000000..1689f9d --- /dev/null +++ b/gems/activefunction-controller/sig/active_function_controller/rendering.rbs @@ -0,0 +1,18 @@ +module ActiveFunction::Controller + class DoubleRenderError < Error + MESSAGE_TEMPLATE: String + + attr_reader message: String + + def initialize: (String context) -> void + end + + module Rendering : Core + include _Controller + + DEFAULT_HEADER: Hash[String, String] + @performed: bool + + def render: (?status: ::Integer, ?json: hash, ?head: hash) -> void + end +end diff --git a/gems/activefunction-controller/sig/active_function_controller/response.rbs b/gems/activefunction-controller/sig/active_function_controller/response.rbs new file mode 100644 index 0000000..6269227 --- /dev/null +++ b/gems/activefunction-controller/sig/active_function_controller/response.rbs @@ -0,0 +1,18 @@ +module ActiveFunction + module Controller + class Response + type responseHash = {statusCode: Integer, body: String | nil, headers: Hash[String, String]} + + attr_accessor status: Integer + attr_accessor body: String | nil + attr_accessor headers: Hash[String, String] + + @committed: bool + + def initialize: (?status: Integer, ?body: String | nil, ?headers: Hash[String, String]) -> void + def to_h: -> responseHash + def commit!: -> void + def committed?: -> bool + end + end +end diff --git a/gems/activefunction-controller/sig/active_function_controller/strong_parameters.rbs b/gems/activefunction-controller/sig/active_function_controller/strong_parameters.rbs new file mode 100644 index 0000000..300cb5a --- /dev/null +++ b/gems/activefunction-controller/sig/active_function_controller/strong_parameters.rbs @@ -0,0 +1,46 @@ +module ActiveFunction::Controller + class ParameterMissingError < Error + MESSAGE_TEMPLATE: String + + attr_reader message: String + + def initialize: (untyped param) -> void + end + + class UnpermittedParameterError < Error + MESSAGE_TEMPLATE: String + + attr_reader message: String + + def initialize: (untyped param) -> void + end + module StrongParameters : Core + include _Controller + + @_params: Parameters + + def params: -> Parameters + + class Parameters + extend Forwardable + @permitted: bool + @parameters: hash + + def initialize: (hash parameters, ?permitted: bool) -> void + def []: (Symbol attribute) -> (Array[Parameters] | Parameters) + def require: (Symbol attribute) -> (Array[Parameters] | Parameters) + def permit: (*untyped attributes) -> Parameters + def to_h: -> hash + + private + + def nested_attribute: (hash attribute) -> Parameters + | (Array[hash] attribute) -> Array[Parameters] + | (untyped attribute) -> untyped + + def process_nested: (untyped attr, Symbol method, ?Array[Symbol] options) -> (Parameters | Array[Parameters] | untyped) + + attr_reader parameters: hash + end + end +end diff --git a/gems/activefunction-controller/sig/manifest.yml b/gems/activefunction-controller/sig/manifest.yml new file mode 100644 index 0000000..014c2aa --- /dev/null +++ b/gems/activefunction-controller/sig/manifest.yml @@ -0,0 +1,3 @@ +dependencies: + - name: json + - name: forwardable diff --git a/gems/activefunction-controller/sig/typeprof.rb b/gems/activefunction-controller/sig/typeprof.rb new file mode 100644 index 0000000..433db4e --- /dev/null +++ b/gems/activefunction-controller/sig/typeprof.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require "active_function" + +function = Class.new(ActiveFunction::Controller::Base) do + before_action :action, only: :index, if: :condition? + after_action :action, only: :index, if: :condition? + + def index + permitted_params = params.require(:bodt).permit(:name, :id) + render json: permitted_params, status: 200 + end + + private + + def condition? + true + end +end + +function.process(:index, request: {body: {name: "John", id: 1}}) diff --git a/gems/activefunction-controller/test/active_function_test.rb b/gems/activefunction-controller/test/active_function_test.rb new file mode 100644 index 0000000..9c7757e --- /dev/null +++ b/gems/activefunction-controller/test/active_function_test.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +require "test_helper" + +class TestFunction < ActiveFunction::Controller::Base + def index + render json: {a: 1, b: 2}, status: 201, head: {"X-Test" => "test"} + end +end + +class TestFunctionWithCallbacks < ActiveFunction::Controller::Base + before_action :set_first + + def index + render json: {first: @first} + end + + private + + def set_first + @first = 1 + end +end + +class TestFunctionWithParameters < ActiveFunction::Controller::Base + def index + render json: params.require(:data).permit(:id, message: %i[text]).to_h + end +end + +class ActiveFunctionTest < Minitest::Test + def test_function_processing + response = TestFunction.process(:index, {}) + + assert_equal(response, { + statusCode: 201, + body: {a: 1, b: 2}.to_json, + headers: {"Content-Type" => "application/json", "X-Test" => "test"} + }) + end + + def test_function_processing_with_callbacks + response = TestFunctionWithCallbacks.process(:index, {}) + + assert_equal(response, { + statusCode: 200, + body: {first: 1}.to_json, + headers: {"Content-Type" => "application/json"} + }) + end + + def test_function_processing_with_inheritted_callbacks + response = Class.new(TestFunctionWithCallbacks).process(:index, {}) + + assert_equal(response, { + statusCode: 200, + body: {first: 1}.to_json, + headers: {"Content-Type" => "application/json"} + }) + end + + def test_function_processing_with_params + data = {data: {id: 1, name: "Pupa", message: {id: 1, text: "test"}}} + + response = TestFunctionWithParameters.process(:index, data) + + assert_equal(response, { + statusCode: 200, + body: {id: 1, message: {text: "test"}}.to_json, + headers: {"Content-Type" => "application/json"} + }) + end +end diff --git a/gems/activefunction-controller/test/fixtures/aws_events/api_gateway_http.json b/gems/activefunction-controller/test/fixtures/aws_events/api_gateway_http.json new file mode 100644 index 0000000..7919cc1 --- /dev/null +++ b/gems/activefunction-controller/test/fixtures/aws_events/api_gateway_http.json @@ -0,0 +1,101 @@ +{ + "resource": "/", + "path": "/", + "httpMethod": "GET", + "headers": { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", + "accept-encoding": "gzip, deflate, br", + "accept-language": "en-US,en;q=0.9", + "cookie": "s_fid=7AAB6XMPLAFD9BBF-0643XMPL09956DE2; regStatus=pre-register", + "Host": "70ixmpl4fl.execute-api.us-east-2.amazonaws.com", + "sec-fetch-dest": "document", + "sec-fetch-mode": "navigate", + "sec-fetch-site": "none", + "upgrade-insecure-requests": "1", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36", + "X-Amzn-Trace-Id": "Root=1-5e66d96f-7491f09xmpl79d18acf3d050", + "X-Forwarded-For": "52.255.255.12", + "X-Forwarded-Port": "443", + "X-Forwarded-Proto": "https" + }, + "multiValueHeaders": { + "accept": [ + "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" + ], + "accept-encoding": [ + "gzip, deflate, br" + ], + "accept-language": [ + "en-US,en;q=0.9" + ], + "cookie": [ + "s_fid=7AABXMPL1AFD9BBF-0643XMPL09956DE2; regStatus=pre-register;" + ], + "Host": [ + "70ixmpl4fl.execute-api.ca-central-1.amazonaws.com" + ], + "sec-fetch-dest": [ + "document" + ], + "sec-fetch-mode": [ + "navigate" + ], + "sec-fetch-site": [ + "none" + ], + "upgrade-insecure-requests": [ + "1" + ], + "User-Agent": [ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36" + ], + "X-Amzn-Trace-Id": [ + "Root=1-5e66d96f-7491f09xmpl79d18acf3d050" + ], + "X-Forwarded-For": [ + "52.255.255.12" + ], + "X-Forwarded-Port": [ + "443" + ], + "X-Forwarded-Proto": [ + "https" + ] + }, + "queryStringParameters": null, + "multiValueQueryStringParameters": null, + "pathParameters": null, + "stageVariables": null, + "requestContext": { + "resourceId": "2gxmpl", + "resourcePath": "/", + "httpMethod": "GET", + "extendedRequestId": "JJbxmplHYosFVYQ=", + "requestTime": "10/Mar/2020:00:03:59 +0000", + "path": "/Prod/", + "accountId": "123456789012", + "protocol": "HTTP/1.1", + "stage": "Prod", + "domainPrefix": "70ixmpl4fl", + "requestTimeEpoch": 1583798639428, + "requestId": "77375676-xmpl-4b79-853a-f982474efe18", + "identity": { + "cognitoIdentityPoolId": null, + "accountId": null, + "cognitoIdentityId": null, + "caller": null, + "sourceIp": "52.255.255.12", + "principalOrgId": null, + "accessKey": null, + "cognitoAuthenticationType": null, + "cognitoAuthenticationProvider": null, + "userArn": null, + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36", + "user": null + }, + "domainName": "70ixmpl4fl.execute-api.us-east-2.amazonaws.com", + "apiId": "70ixmpl4fl" + }, + "body": null, + "isBase64Encoded": false +} diff --git a/gems/activefunction-controller/test/fixtures/aws_events/dynamodb.json b/gems/activefunction-controller/test/fixtures/aws_events/dynamodb.json new file mode 100644 index 0000000..1089670 --- /dev/null +++ b/gems/activefunction-controller/test/fixtures/aws_events/dynamodb.json @@ -0,0 +1,64 @@ +{ + "Records": [ + { + "eventID": "1", + "eventVersion": "1.0", + "dynamodb": { + "Keys": { + "Id": { + "N": "101" + } + }, + "NewImage": { + "Message": { + "S": "New item!" + }, + "Id": { + "N": "101" + } + }, + "StreamViewType": "NEW_AND_OLD_IMAGES", + "SequenceNumber": "111", + "SizeBytes": 26 + }, + "awsRegion": "us-west-2", + "eventName": "INSERT", + "eventSourceARN": "arn:aws:dynamodb:us-west-2:111122223333:table/TestTable/stream/2015-05-11T21:21:33.291", + "eventSource": "aws:dynamodb" + }, + { + "eventID": "2", + "eventVersion": "1.0", + "dynamodb": { + "OldImage": { + "Message": { + "S": "New item!" + }, + "Id": { + "N": "101" + } + }, + "SequenceNumber": "222", + "Keys": { + "Id": { + "N": "101" + } + }, + "SizeBytes": 59, + "NewImage": { + "Message": { + "S": "This item has changed" + }, + "Id": { + "N": "101" + } + }, + "StreamViewType": "NEW_AND_OLD_IMAGES" + }, + "awsRegion": "us-west-2", + "eventName": "MODIFY", + "eventSourceARN": "arn:aws:dynamodb:us-west-2:111122223333:table/TestTable/stream/2015-05-11T21:21:33.291", + "eventSource": "aws:dynamodb" + } + ] +} \ No newline at end of file diff --git a/gems/activefunction-controller/test/functions/callbacks_test.rb b/gems/activefunction-controller/test/functions/callbacks_test.rb new file mode 100644 index 0000000..b16d4b6 --- /dev/null +++ b/gems/activefunction-controller/test/functions/callbacks_test.rb @@ -0,0 +1,171 @@ +# frozen_string_literal: true + +require "test_helper" + +class CallbackTestFunction + include ActiveFunction::Controller::Core + include ActiveFunction::Controller::Callbacks + + def index + nil + end + + def show + nil + end + + private # callback methods + + def first + @first = "Biba" + end + + def second + @second = "Boba" + end +end + +class CallbackTestFunction1 < CallbackTestFunction + set_callback :before, :first +end + +class CallbackTest1 < Minitest::Test + def setup + @function = CallbackTestFunction1.new + end + + def test_callback + @function.dispatch(:index, {}, committed_response) + + assert_equal @function.instance_variable_get(:@first), "Biba" + end +end + +class CallbackTestFunction2 < CallbackTestFunction + before_action :first + after_action :second +end + +class CallbackTestFunction2Inherit < CallbackTestFunction2 +end + +class CallbackTest2 < Minitest::Test + def setup + @function = CallbackTestFunction2.new + end + + def test_before_action_callback + @function.dispatch(:index, {}, committed_response) + + assert_equal @function.instance_variable_get(:@first), "Biba" + end + + def test_after_action_callback + @function.dispatch(:index, {}, committed_response) + + assert_equal @function.instance_variable_get(:@second), "Boba" + end + + def test_inherit_callbacks + @function = CallbackTestFunction2Inherit.new + + @function.dispatch(:index, {}, committed_response) + + assert_equal @function.instance_variable_get(:@first), "Biba" + assert_equal @function.instance_variable_get(:@second), "Boba" + end +end + +class ConditionalCallbacksTestFunction1 < CallbackTestFunction + before_action :first, only: %i[index] + after_action :second, only: %i[show] +end + +class ConditionalCallbacksTest1 < Minitest::Test + def setup + @function = ConditionalCallbacksTestFunction1.new + end + + def test_before_action_callback + @function.dispatch(:index, {}, committed_response) + + assert_equal @function.instance_variable_get(:@first), "Biba" + assert_nil @function.instance_variable_get(:@second) + end + + def test_after_action_callback + @function.dispatch(:show, {}, committed_response) + + assert_equal @function.instance_variable_get(:@second), "Boba" + end +end + +class ConditionalCallbacksTestFunction2 < CallbackTestFunction + before_action :first, only: %i[show index] +end + +class ConditionalCallbacksTest2 < Minitest::Test + def setup + @function = ConditionalCallbacksTestFunction2.new + end + + def test_callback_for_index_action + @function.dispatch(:index, {}, committed_response) + + assert_equal @function.instance_variable_get(:@first), "Biba" + end + + def test_callback_for_show_action + @function.dispatch(:show, {}, committed_response) + + assert_equal @function.instance_variable_get(:@first), "Biba" + end +end + +class ConditionalCallbacksTestFunction3 < CallbackTestFunction + before_action :first, if: :executable? + after_action :second, if: :not_executable? + + private + + def executable? + false + end + + def not_executable? + true + end +end + +class ConditionalCallbacksTest3 < Minitest::Test + def setup + @function = ConditionalCallbacksTestFunction3.new + end + + def test_if_before_action_callback + @function.dispatch(:index, {}, committed_response) + + assert_nil @function.instance_variable_get(:@first) + assert_equal @function.instance_variable_get(:@second), "Boba" + end +end + +class ConditionalCallbacksTestFunction4 < CallbackTestFunction + before_action :first, only: %i[index], if: :executable? + + private def executable? + true + end +end + +class ConditionalCallbacksTest4 < Minitest::Test + def setup + @function = ConditionalCallbacksTestFunction4.new + end + + def test_callback_with_all_condition_options + @function.dispatch(:index, {}, committed_response) + + assert_equal @function.instance_variable_get(:@first), "Biba" + end +end diff --git a/gems/activefunction-controller/test/functions/core_test.rb b/gems/activefunction-controller/test/functions/core_test.rb new file mode 100644 index 0000000..78b31a9 --- /dev/null +++ b/gems/activefunction-controller/test/functions/core_test.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require "test_helper" + +class CoreTestFunction + include ActiveFunction::Controller::Core + + def index + nil + end +end + +class CoreTest < Minitest::Test + def setup + @function = CoreTestFunction.new + end + + def test_action_to_be_called + mock = Minitest::Mock.new + mock.expect(:call, nil) + + @function.stub(:index, mock) do + @function.dispatch(:index, {body: {}}, committed_response) + end + + mock.verify + end + + def test_dispatch_raises_error_if_route_is_not_defined + assert_raises ActiveFunction::Controller::MissingRouteMethod do + @function.dispatch(:show, {}, response) + end + end + + def test_dispatch_raises_error_if_render_was_not_called + assert_raises ActiveFunction::Controller::NotRenderedError do + @function.dispatch(:index, {}, response) + end + end +end diff --git a/gems/activefunction-controller/test/functions/rendering_test.rb b/gems/activefunction-controller/test/functions/rendering_test.rb new file mode 100644 index 0000000..e18a6da --- /dev/null +++ b/gems/activefunction-controller/test/functions/rendering_test.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true + +require "test_helper" + +class RenderingTestFunction + include ActiveFunction::Controller::Core + include ActiveFunction::Controller::Rendering + + def index + render + end +end + +class RenderingTest < Minitest::Test + def setup + @function = RenderingTestFunction.new + end + + def test_render_default_response + @function.dispatch(:index, {}, response) + + response = @function.instance_variable_get(:@response) + + assert_equal response.status, 200 + assert_equal response.headers, {"Content-Type" => "application/json"} + assert_equal response.body, "{}" + end +end + +class DoubleRenderTestFunction < RenderingTestFunction + def index + super + render + end +end + +class DoubleRenderTest < Minitest::Test + def setup + @function = DoubleRenderTestFunction.new + end + + def test_double_render + assert_raises ActiveFunction::Controller::DoubleRenderError do + @function.dispatch(:index, {}, response) + end + end +end + +class RenderCustomResponseTestFunction < RenderingTestFunction + def index + render json: {a: 1, b: 2}, head: {"X-Test" => "test"}, status: 201 + end +end + +class RenderCustomResponseTest < Minitest::Test + def setup + @function = RenderCustomResponseTestFunction.new + end + + def test_render_custom_response + @function.dispatch(:index, {}, response) + + response = @function.instance_variable_get(:@response) + + assert_equal response.status, 201 + assert_equal response.headers, {"Content-Type" => "application/json", "X-Test" => "test"} + assert_equal response.body, '{"a":1,"b":2}' + end +end + +class NotRenderedTestFunction + include ActiveFunction::Controller::Core + include ActiveFunction::Controller::Rendering + + def index + nil + end +end + +class NotRenderedTest < Minitest::Test + def setup + @function = NotRenderedTestFunction.new + end + + def test_not_rendered + assert_raises ActiveFunction::Controller::NotRenderedError do + @function.dispatch(:index, {}, response) + end + end +end diff --git a/gems/activefunction-controller/test/functions/response_test.rb b/gems/activefunction-controller/test/functions/response_test.rb new file mode 100644 index 0000000..0285cb5 --- /dev/null +++ b/gems/activefunction-controller/test/functions/response_test.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require "test_helper" + +class ResponseTest < Minitest::Test + def setup + @response = ActiveFunction::Controller::Response.new + end + + def test_status + @response.status = 201 + + assert_equal @response.status, 201 + end + + def test_headers + @response.headers = {"X-Test" => "test"} + + assert_equal @response.headers, {"X-Test" => "test"} + end + + def test_body + @response.body = "test" + + assert_equal @response.body, "test" + end + + def test_to_h + @response.status = 201 + @response.headers = {"X-Test" => "test"} + @response.body = "test" + + assert_equal @response.to_h, {statusCode: 201, headers: {"X-Test" => "test"}, body: "test"} + end + + def test_commit! + assert_equal @response.committed?, false + + @response.commit! + + assert_equal @response.committed?, true + end +end diff --git a/gems/activefunction-controller/test/functions/strong_parameters_test.rb b/gems/activefunction-controller/test/functions/strong_parameters_test.rb new file mode 100644 index 0000000..e7101c1 --- /dev/null +++ b/gems/activefunction-controller/test/functions/strong_parameters_test.rb @@ -0,0 +1,200 @@ +# frozen_string_literal: true + +require "test_helper" + +class StrongParametersFunction + include ActiveFunction::Controller::Core + include ActiveFunction::Controller::StrongParameters +end + +class StrongParametersTest < Minitest::Test + def setup + @function = StrongParametersFunction.new + end + + def test_params + assert_instance_of ActiveFunction::Controller::StrongParameters::Parameters, @function.params + end +end + +describe ActiveFunction::Controller::StrongParameters::Parameters do + let(:described_class) { ::ActiveFunction::Controller::StrongParameters::Parameters } + + def assert_nested_params(expected, actual) + assert_equal expected, actual.instance_variable_get(:@parameters) + end + + describe "#[]" do + it "returns the value of the parameter when it exists" do + params = described_class.new({name: "Pupa"}) + + assert_equal "Pupa", params[:name] + end + + it "returns Parameter instance if the parameter is a hash" do + params = described_class.new({user: {name: "Pupa"}}) + nested_params = params[:user] + + assert_instance_of described_class, nested_params + end + + it "returns array of Parameter instances if the parameter is an array of hashes" do + params = described_class.new({users: [{name: "Pupa"}, {name: "Lupa"}]}) + nested_params = params[:users] + + assert_instance_of Array, nested_params + assert_instance_of described_class, nested_params[0] + assert_instance_of described_class, nested_params[1] + end + + it "returns the value of the nested parameter when it exists" do + params = described_class.new({user: {name: "Pupa"}}) + + assert_nested_params({name: "Pupa"}, params[:user]) + end + + it "returns nested parameters when they exist" do + params = described_class.new({user: {name: "Pupa"}}) + nested_params = params[:user][:name] + + assert_equal "Pupa", nested_params + end + + it "returns nil when the parameter does not exist" do + params = described_class.new({}) + + assert_nil params[:name] + end + + it "returns nil when the nested parameter does not exist" do + params = described_class.new({user: {}}) + + assert_nil params[:user][:name] + end + end + + describe "#require" do + it "returns the value of the parameter when it exists" do + params = described_class.new({name: "Pupa"}) + + assert_equal "Pupa", params.require(:name) + end + + it "returns Parameter instance if the parameter is a hash" do + params = described_class.new({user: {name: "Pupa"}}) + required_params = params.require(:user) + + assert_instance_of described_class, required_params + end + + it "returns array of Parameter instances if the parameter is an array of hashes" do + params = described_class.new({users: [{name: "Pupa"}, {name: "Lupa"}]}) + required_params = params.require(:users) + + assert_instance_of Array, required_params + assert_instance_of described_class, required_params[0] + assert_instance_of described_class, required_params[1] + end + + it "returns the value of the nested parameter when it exists" do + params = described_class.new({user: {name: "Pupa"}}) + + assert_nested_params({name: "Pupa"}, params.require(:user)) + end + + it "returns nested parameters when they exist" do + params = described_class.new({user: {name: "Pupa"}}) + required_params = params.require(:user).require(:name) + + assert_equal "Pupa", required_params + end + + it "raises a ParameterMissingError when the parameter does not exist" do + params = described_class.new({}) + + assert_raises(ActiveFunction::Controller::ParameterMissingError) { params.require(:name) } + end + end + + describe "#permit" do + it "returns new Parameters instance with permitted parameters" do + params = described_class.new({id: 1, name: "Pupa"}) + permitted_params = params.permit(:id, :name) + + assert_instance_of described_class, permitted_params + assert_equal true, permitted_params.instance_variable_get(:@permitted) + assert_nested_params({id: 1, name: "Pupa"}, permitted_params) + end + + it "returns new Parameters instances with permitted nested parameters" do + params = described_class.new({user: {name: "Pupa", roles: [{id: 1, name: "Admin"}]}}) + permitted_params = params.permit(user: [:name, roles: [:id, :name]]) + + assert_instance_of described_class, permitted_params + assert_instance_of described_class, permitted_params[:user] + assert_instance_of described_class, permitted_params[:user][:roles][0] + + assert_equal true, permitted_params.instance_variable_get(:@permitted) + assert_equal true, permitted_params[:user].instance_variable_get(:@permitted) + assert_equal true, permitted_params[:user][:roles][0].instance_variable_get(:@permitted) + end + + it "returns new Parameters instance with valid values in nested parameters" do + params = described_class.new({user: {name: "Pupa", roles: [{id: 1, name: "Admin"}]}}) + permitted_params = params.permit(user: [:name, roles: [:id, :name]]) + + assert_equal "Pupa", permitted_params[:user][:name] + assert_nested_params({id: 1, name: "Admin"}, permitted_params[:user][:roles][0]) + end + + it "ignores parameter when the it does not exist" do + params = described_class.new({}) + + assert_nested_params({}, params.permit(:name)) + end + + it "ignores nested parameter when the it does not exist" do + params = described_class.new({user: {}}) + permitted_params = params.permit(user: [:name]) + + assert_nested_params({}, permitted_params[:user]) + end + end + + describe "#to_h" do + it "returns hash with permitted parameters" do + params = described_class.new({id: 1, name: "Pupa"}) + permitted_params = params.permit(:id, :name) + + assert_equal({id: 1, name: "Pupa"}, permitted_params.to_h) + end + + it "returns hash with permitted nested parameters" do + params = described_class.new({user: {name: "Pupa", roles: [{name: "Admin"}]}}) + permitted_params = params.permit(user: [:name, roles: [:id, :name]]) + + assert_equal({user: {name: "Pupa", roles: [{name: "Admin"}]}}, permitted_params.to_h) + end + + it "returns hash with permitted nested parameters when the parameter is an array of hashes" do + params = described_class.new({users: [{id: 1, name: "Pupa"}, {id:2, name: "Lupa"}]}) + permitted_params = params.permit(users: [:name]) + + assert_equal({users: [{name: "Pupa"}, {name: "Lupa"}]}, permitted_params.to_h) + end + + it "returns hash with permitted nested parameters when the parameter is an array of hashes with nested parameters" do + params = described_class.new({users: [{name: "Pupa", roles: [{id: 1, name: "Admin"}]}, {name: "Lupa", roles: [{id: 2, name: "User"}]}]}) + permitted_params = params.permit(users: [:name, roles: [:name]]) + + assert_equal({users: [{name: "Pupa", roles: [{name: "Admin"}]}, {name: "Lupa", roles: [{name: "User"}]}]}, permitted_params.to_h) + end + + # test UnpermittedParameterError case when the parameter is an array of hashes with nested parameters + it "raises UnpermittedParameterError when some parameter is not permitted" do + params = described_class.new({name: "Pupa"}) + + assert_raises(ActiveFunction::Controller::UnpermittedParameterError) { params.to_h } + end + end +end diff --git a/gems/activefunction-controller/test/support/active_function_helper.rb b/gems/activefunction-controller/test/support/active_function_helper.rb new file mode 100644 index 0000000..050fc3b --- /dev/null +++ b/gems/activefunction-controller/test/support/active_function_helper.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module ActiveFunctionHelper + def response + ActiveFunction::Controller::Response.new + end + + def committed_response + response.tap(&:commit!) + end +end + +Minitest::Test.include ActiveFunctionHelper diff --git a/gems/activefunction-controller/test/test_helper.rb b/gems/activefunction-controller/test/test_helper.rb new file mode 100644 index 0000000..62cbc09 --- /dev/null +++ b/gems/activefunction-controller/test/test_helper.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require "bundler/setup" +require "ruby-next/language/runtime" unless ENV["CI"] + +require "minitest/autorun" +require "minitest/reporters" + +require "active_function_controller" + +require "./test/support/active_function_helper" + +Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new(color: true)] From d22c634c5ce9ce36d0e49aa0accccaf52357780e Mon Sep 17 00:00:00 2001 From: Nerbyk Date: Sun, 20 Aug 2023 15:15:22 +0700 Subject: [PATCH 3/8] =?UTF-8?q?Prevent=20breaking=20backcompatability=20?= =?UTF-8?q?=E2=80=93=20Rollback=20root=20gem=20structure?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../.github => .github}/workflows/CI.yml | 0 .../.github => .github}/workflows/lint.yml | 0 .../.gitignore => .gitignore | 0 .../.rbnextrc => .rbnextrc | 0 .../.rubocop.yml => .rubocop.yml | 0 .../CHANGELOG.md => CHANGELOG.md | 12 +- .../Gemfile => Gemfile | 0 .../README.md => README.md | 25 +++-- .../Rakefile => Rakefile | 0 .../Steepfile => Steepfile | 4 +- ...ntroller.gemspec => activefunction.gemspec | 20 ++-- .../bin => bin}/console | 2 +- bin/rake | 27 +++++ .../bin => bin}/rubocop | 0 .../bin => bin}/setup | 0 .../gemfiles => gemfiles}/rbs.gemfile | 0 .../gemfiles => gemfiles}/rubocop.gemfile | 0 .../CODE_OF_CONDUCT.md | 84 -------------- .../strong_parameters.rb | 102 ----------------- .../3.0/active_function_controller/core.rb | 47 -------- .../active_function_controller/response.rb | 28 ----- .../lib/active_function_controller.rb | 26 ----- .../active_function_controller/callbacks.rb | 67 ----------- .../lib/active_function_controller/core.rb | 47 -------- .../active_function_controller/rendering.rb | 29 ----- .../active_function_controller/response.rb | 28 ----- .../strong_parameters.rb | 102 ----------------- .../sig/active_function_controller.rbs | 19 ---- .../active_function_controller/rendering.rbs | 18 --- .../functions/strong_parameters.rb | 104 ++++++++++++++++++ .../3.0/active_function/functions/core.rb | 49 +++++++++ .../3.0/active_function/functions/response.rb | 30 +++++ .../active_function.rb | 3 +- lib/active_function/base.rb | 20 ++++ lib/active_function/functions/callbacks.rb | 69 ++++++++++++ lib/active_function/functions/core.rb | 49 +++++++++ lib/active_function/functions/rendering.rb | 31 ++++++ lib/active_function/functions/response.rb | 30 +++++ .../functions/strong_parameters.rb | 104 ++++++++++++++++++ .../active_function}/version.rb | 4 +- sig/active_function.rbs | 4 + sig/active_function/base.rbs | 14 +++ .../active_function/functions}/callbacks.rbs | 6 +- .../active_function/functions}/core.rbs | 7 +- sig/active_function/functions/rendering.rbs | 20 ++++ .../active_function/functions}/response.rbs | 2 +- .../functions}/strong_parameters.rbs | 7 +- sig/aws_events/apiGatewayAuthorizerEvent.rbs | 5 + sig/aws_events/apiGatewayV2HTTPEvent.rbs | 81 ++++++++++++++ sig/aws_events/awsCongigEvent.rbs | 12 ++ sig/aws_events/cloudWatchLogsEvent.rbs | 22 ++++ sig/aws_events/codeCommitEvent.rbs | 25 +++++ sig/aws_events/cognitoEvent.rbs | 15 +++ sig/aws_events/dynamoDBEvent.rbs | 30 +++++ sig/aws_events/kinesisEvent.rbs | 16 +++ sig/aws_events/kinesisFirehoseEvent.rbs | 19 ++++ sig/aws_events/s3Event.rbs | 31 ++++++ sig/aws_events/sesEvent.rbs | 59 ++++++++++ sig/aws_events/snsEvent.rbs | 25 +++++ sig/aws_events/sqsEvent.rbs | 20 ++++ .../sig => sig}/manifest.yml | 0 .../sig => sig}/typeprof.rb | 2 +- .../test => test}/active_function_test.rb | 6 +- .../fixtures/aws_events/api_gateway_http.json | 0 .../fixtures/aws_events/dynamodb.json | 0 .../test => test}/functions/callbacks_test.rb | 4 +- .../test => test}/functions/core_test.rb | 6 +- .../test => test}/functions/rendering_test.rb | 12 +- .../test => test}/functions/response_test.rb | 2 +- .../functions/strong_parameters_test.rb | 14 +-- .../support/active_function_helper.rb | 2 +- .../test => test}/test_helper.rb | 2 +- 72 files changed, 985 insertions(+), 665 deletions(-) rename {gems/activefunction-controller/.github => .github}/workflows/CI.yml (100%) rename {gems/activefunction-controller/.github => .github}/workflows/lint.yml (100%) rename gems/activefunction-controller/.gitignore => .gitignore (100%) rename gems/activefunction-controller/.rbnextrc => .rbnextrc (100%) rename gems/activefunction-controller/.rubocop.yml => .rubocop.yml (100%) rename gems/activefunction-controller/CHANGELOG.md => CHANGELOG.md (65%) rename gems/activefunction-controller/Gemfile => Gemfile (100%) rename gems/activefunction-controller/README.md => README.md (80%) rename gems/activefunction-controller/Rakefile => Rakefile (100%) rename gems/activefunction-controller/Steepfile => Steepfile (80%) rename gems/activefunction-controller/active_function_controller.gemspec => activefunction.gemspec (67%) rename {gems/activefunction-controller/bin => bin}/console (90%) create mode 100755 bin/rake rename {gems/activefunction-controller/bin => bin}/rubocop (100%) rename {gems/activefunction-controller/bin => bin}/setup (100%) rename {gems/activefunction-controller/gemfiles => gemfiles}/rbs.gemfile (100%) rename {gems/activefunction-controller/gemfiles => gemfiles}/rubocop.gemfile (100%) delete mode 100644 gems/activefunction-controller/CODE_OF_CONDUCT.md delete mode 100644 gems/activefunction-controller/lib/.rbnext/2.7/active_function_controller/strong_parameters.rb delete mode 100644 gems/activefunction-controller/lib/.rbnext/3.0/active_function_controller/core.rb delete mode 100644 gems/activefunction-controller/lib/.rbnext/3.0/active_function_controller/response.rb delete mode 100644 gems/activefunction-controller/lib/active_function_controller.rb delete mode 100644 gems/activefunction-controller/lib/active_function_controller/callbacks.rb delete mode 100644 gems/activefunction-controller/lib/active_function_controller/core.rb delete mode 100644 gems/activefunction-controller/lib/active_function_controller/rendering.rb delete mode 100644 gems/activefunction-controller/lib/active_function_controller/response.rb delete mode 100644 gems/activefunction-controller/lib/active_function_controller/strong_parameters.rb delete mode 100644 gems/activefunction-controller/sig/active_function_controller.rbs delete mode 100644 gems/activefunction-controller/sig/active_function_controller/rendering.rbs create mode 100644 lib/.rbnext/2.7/active_function/functions/strong_parameters.rb create mode 100644 lib/.rbnext/3.0/active_function/functions/core.rb create mode 100644 lib/.rbnext/3.0/active_function/functions/response.rb rename gems/activefunction-core/lib/active_function_core.rb => lib/active_function.rb (74%) create mode 100644 lib/active_function/base.rb create mode 100644 lib/active_function/functions/callbacks.rb create mode 100644 lib/active_function/functions/core.rb create mode 100644 lib/active_function/functions/rendering.rb create mode 100644 lib/active_function/functions/response.rb create mode 100644 lib/active_function/functions/strong_parameters.rb rename {gems/activefunction-controller/lib/active_function_controller => lib/active_function}/version.rb (54%) create mode 100644 sig/active_function.rbs create mode 100644 sig/active_function/base.rbs rename {gems/activefunction-controller/sig/active_function_controller => sig/active_function/functions}/callbacks.rbs (93%) rename {gems/activefunction-controller/sig/active_function_controller => sig/active_function/functions}/core.rbs (89%) create mode 100644 sig/active_function/functions/rendering.rbs rename {gems/activefunction-controller/sig/active_function_controller => sig/active_function/functions}/response.rbs (96%) rename {gems/activefunction-controller/sig/active_function_controller => sig/active_function/functions}/strong_parameters.rbs (94%) create mode 100644 sig/aws_events/apiGatewayAuthorizerEvent.rbs create mode 100644 sig/aws_events/apiGatewayV2HTTPEvent.rbs create mode 100644 sig/aws_events/awsCongigEvent.rbs create mode 100644 sig/aws_events/cloudWatchLogsEvent.rbs create mode 100644 sig/aws_events/codeCommitEvent.rbs create mode 100644 sig/aws_events/cognitoEvent.rbs create mode 100644 sig/aws_events/dynamoDBEvent.rbs create mode 100644 sig/aws_events/kinesisEvent.rbs create mode 100644 sig/aws_events/kinesisFirehoseEvent.rbs create mode 100644 sig/aws_events/s3Event.rbs create mode 100644 sig/aws_events/sesEvent.rbs create mode 100644 sig/aws_events/snsEvent.rbs create mode 100644 sig/aws_events/sqsEvent.rbs rename {gems/activefunction-controller/sig => sig}/manifest.yml (100%) rename {gems/activefunction-controller/sig => sig}/typeprof.rb (87%) rename {gems/activefunction-controller/test => test}/active_function_test.rb (89%) rename {gems/activefunction-controller/test => test}/fixtures/aws_events/api_gateway_http.json (100%) rename {gems/activefunction-controller/test => test}/fixtures/aws_events/dynamodb.json (100%) rename {gems/activefunction-controller/test => test}/functions/callbacks_test.rb (97%) rename {gems/activefunction-controller/test => test}/functions/core_test.rb (78%) rename {gems/activefunction-controller/test => test}/functions/rendering_test.rb (84%) rename {gems/activefunction-controller/test => test}/functions/response_test.rb (93%) rename {gems/activefunction-controller/test => test}/functions/strong_parameters_test.rb (92%) rename {gems/activefunction-controller/test => test}/support/active_function_helper.rb (80%) rename {gems/activefunction-controller/test => test}/test_helper.rb (88%) diff --git a/gems/activefunction-controller/.github/workflows/CI.yml b/.github/workflows/CI.yml similarity index 100% rename from gems/activefunction-controller/.github/workflows/CI.yml rename to .github/workflows/CI.yml diff --git a/gems/activefunction-controller/.github/workflows/lint.yml b/.github/workflows/lint.yml similarity index 100% rename from gems/activefunction-controller/.github/workflows/lint.yml rename to .github/workflows/lint.yml diff --git a/gems/activefunction-controller/.gitignore b/.gitignore similarity index 100% rename from gems/activefunction-controller/.gitignore rename to .gitignore diff --git a/gems/activefunction-controller/.rbnextrc b/.rbnextrc similarity index 100% rename from gems/activefunction-controller/.rbnextrc rename to .rbnextrc diff --git a/gems/activefunction-controller/.rubocop.yml b/.rubocop.yml similarity index 100% rename from gems/activefunction-controller/.rubocop.yml rename to .rubocop.yml diff --git a/gems/activefunction-controller/CHANGELOG.md b/CHANGELOG.md similarity index 65% rename from gems/activefunction-controller/CHANGELOG.md rename to CHANGELOG.md index 5074aef..f3d2b49 100644 --- a/gems/activefunction-controller/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,9 +3,9 @@ ## [0.1.0] - 2022-12-28 - Add `before_action` and `after_action` callbacks with `:only` and `:if` options -- Add `ActiveFunction::Controller::Base#params` with `require`, `permit`, `[]` and `to_h` public methods -- Add specs for `ActiveFunction::Controller::Base.params` module -- Add `ActiveFunction::Controller::Base#render` with `:status`, `:json` and `:head` options +- Add `ActiveFunction::Base#params` with `require`, `permit`, `[]` and `to_h` public methods +- Add specs for `ActiveFunction::Base.params` module +- Add `ActiveFunction::Base#render` with `:status`, `:json` and `:head` options - Add RBS signature - Add RBS Aws Event Types - Add public interface type `steep` checking @@ -21,9 +21,9 @@ ## [0.3.0] - 2023-01-12 - cleanup -- add ActiveFunction::Controller::Response#commit! -- extract action processing to separate method to handle ActiveFunction::Controller::Callbacks#process overriding -- add test for ActiveFunction::Controller::Base.process +- add ActiveFunction::Functions::Response#commit! +- extract action processing to separate method to handle ActiveFunction::Functions::Callbacks#process overriding +- add test for ActiveFunction::Base.process # [0.3.1] - 2023-02-09 diff --git a/gems/activefunction-controller/Gemfile b/Gemfile similarity index 100% rename from gems/activefunction-controller/Gemfile rename to Gemfile diff --git a/gems/activefunction-controller/README.md b/README.md similarity index 80% rename from gems/activefunction-controller/README.md rename to README.md index 66652bd..c8e65b2 100644 --- a/gems/activefunction-controller/README.md +++ b/README.md @@ -5,14 +5,15 @@ rails/action_controller like gem which provides lightweight callbacks, strong pa Implemented with some of ruby 3.x features, but also supports ruby 2.6.x thanks to [RubyNext](https://github.com/ruby-next/ruby-next) transpiler. Type safety achieved by RBS and [Steep](https://github.com/soutaro/steep). + ## A Short Example -Here's a simple example of a controller that uses ActiveFunction::Controller: +Here's a simple example of a function that uses ActiveFunction: ```ruby -require 'active-function-controller' +require 'active_function' -class AppFunction < ActiveFunction::Controller::Base +class AppFunction < ActiveFunction::Base def index render json: SomeTable.all end @@ -29,7 +30,7 @@ Also check extended [example](https://github.com/DanilMaximov/activefunction/tre ActiveFunction supports simple callbacks `:before` and `:after` which runs around provided action in `#process`. ```ruby -class AppFunction < ActiveFunction::Controller::Base +class AppFunction < ActiveFunction::Base before_action :set_user after_action :log_response @@ -50,7 +51,7 @@ end Callbacks also can be user with `only: Array[Symbol]` and `if: Symbol` options. ```ruby -class AppFunction < ActiveFunction::Controller::Base +class AppFunction < ActiveFunction::Base before_action :set_user, only: %i[show update destroy], if: :request_valid? # some actions ... @@ -61,7 +62,7 @@ end Callbacks are inheritable so all callbacks calls will be inherited from base class ```ruby -class BaseFunction < ActiveFunction::Controller::Base +class BaseFunction < ActiveFunction::Base before_action :set_current_user def set_current_user @@ -84,7 +85,7 @@ PostFunction.process(:index, data: { id: 1, name: "Pupa" }) Simple usage: ```ruby -class PostsFunction < ActiveFunction::Controller::Base +class PostsFunction < ActiveFunction::Base def index render json: permitted_params end @@ -101,9 +102,9 @@ params.permit(:id, :name, :address => [:city, :street]) ``` ## Rendering -ActiveFunction::Controller supports rendering of JSON. Rendering is obligatory for any function naction and can be done by `#render` method. +ActiveFunction supports rendering of JSON. Rendering is obligatory for any function naction and can be done by `#render` method. ```ruby -class PostsFunction < ActiveFunction::Controller::Base +class PostsFunction < ActiveFunction::Base def index render json: { id: 1, name: "Pupa" } end @@ -111,7 +112,7 @@ end ``` default status code is 200, but it can be changed by `:status` option ```ruby -class PostsFunction < ActiveFunction::Controller::Base +class PostsFunction < ActiveFunction::Base def index render json: { id: 1, name: "Pupa" }, status: 201 end @@ -119,7 +120,7 @@ end ``` Headers can be passed by `:headers` option. Default headers are `{"Content-Type" => "application/json"}`. ```ruby -class PostsFunction < ActiveFunction::Controller::Base +class PostsFunction < ActiveFunction::Base def index render json: { id: 1, name: "Pupa" }, headers: { "X-Request-Id" => "123" } end @@ -151,4 +152,4 @@ The gem is available as open source under the terms of the [MIT License](https:/ ## Code of Conduct -Everyone interacting in the ActiveFunction::Controller project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/DanilMaximov/activefunction/blob/master/CODE_OF_CONDUCT.md). +Everyone interacting in the ActiveFunction::Functions project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/DanilMaximov/activefunction/blob/master/CODE_OF_CONDUCT.md). diff --git a/gems/activefunction-controller/Rakefile b/Rakefile similarity index 100% rename from gems/activefunction-controller/Rakefile rename to Rakefile diff --git a/gems/activefunction-controller/Steepfile b/Steepfile similarity index 80% rename from gems/activefunction-controller/Steepfile rename to Steepfile index b47ae5c..a9135f8 100644 --- a/gems/activefunction-controller/Steepfile +++ b/Steepfile @@ -5,14 +5,14 @@ target :lib do check "lib" - ignore "lib/active_function_controller/version.rb" + ignore "lib/active_function/version.rb" # Temporary disable type checking for this file due to: # lib/active_function/functions/strong_parameters.rb:94:44: [error] Unsupported splat node occurrence # │ Diagnostic ID: Ruby::UnsupportedSyntax # │ # └ attribute.map { _1.send(method, *options.to_a) } # ~~~~~~~~~~~~~ - ignore "lib/active_function_controller/strong_parameters.rb" + ignore "lib/active_function/functions/strong_parameters.rb" library( "json", diff --git a/gems/activefunction-controller/active_function_controller.gemspec b/activefunction.gemspec similarity index 67% rename from gems/activefunction-controller/active_function_controller.gemspec rename to activefunction.gemspec index 98e4680..896e90d 100644 --- a/gems/activefunction-controller/active_function_controller.gemspec +++ b/activefunction.gemspec @@ -1,19 +1,19 @@ # frozen_string_literal: true -require_relative "lib/active_function_controller/version" +require_relative "lib/active_function/version" Gem::Specification.new do |spec| - spec.name = "active-function-controller" - spec.version = ActiveFunction::Controller::VERSION + spec.name = "activefunction" + spec.version = ActiveFunction::VERSION spec.authors = ["Nerbyk"] - spec.email = ["danil.maximov2000@gmail.com"] + spec.email = ["danil.maximov2000@gmail.com"] spec.summary = %( - lightweight rails/action_controller clone which provides + rails/action_controller like gem which provides callbacks, strong parameters & rendering features. ) spec.description = %( - lightweight rails/action_controller clone which provides lightweight callbacks, + rails/action_controller like gem which provides lightweight callbacks, strong parameters & rendering features. It's designed to be used with AWS Lambda functions, but can be also used with any Ruby application. @@ -24,12 +24,12 @@ Gem::Specification.new do |spec| spec.homepage = "https://github.com/DanilMaximov/acitvefunction" spec.license = "MIT" spec.metadata = { - "homepage_uri" => "https://github.com/DanilMaximov/activefunction/gems/active-function-controller", - "source_code_uri" => "https://github.com/DanilMaximov/activefunction/gems/active-function-controller", - "changelog_uri" => "https://github.com/DanilMaximov/activefunction/gems/active-function-controller/CHANGELOG.md" + "homepage_uri" => "https://github.com/DanilMaximov/activefunction", + "source_code_uri" => "https://github.com/DanilMaximov/activefunction", + "changelog_uri" => "https://github.com/DanilMaximov/activefunction/CHANGELOG.md" } - spec.files = Dir.glob("lib/**/*") + Dir.glob("lib/.rbnext/**/*") + Dir.glob("bin/**/*") + %w[sig/active_function_controller.rbs sig/manifest.yml] + %w[README.md LICENSE.txt CHANGELOG.md] + spec.files = Dir.glob("lib/**/*") + Dir.glob("lib/.rbnext/**/*") + Dir.glob("bin/**/*") + %w[sig/active_function.rbs sig/manifest.yml] + %w[README.md LICENSE.txt CHANGELOG.md] spec.require_paths = ["lib"] diff --git a/gems/activefunction-controller/bin/console b/bin/console similarity index 90% rename from gems/activefunction-controller/bin/console rename to bin/console index e7821b8..3b6ba05 100755 --- a/gems/activefunction-controller/bin/console +++ b/bin/console @@ -2,7 +2,7 @@ # frozen_string_literal: true require "bundler/setup" -require "activefunction/controller" +require "active_function" # You can add fixtures and/or initialization code here to make experimenting # with your gem easier. You can also use a different console, if you like. diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..51e10c4 --- /dev/null +++ b/bin/rake @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'rake' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("rake", "rake") diff --git a/gems/activefunction-controller/bin/rubocop b/bin/rubocop similarity index 100% rename from gems/activefunction-controller/bin/rubocop rename to bin/rubocop diff --git a/gems/activefunction-controller/bin/setup b/bin/setup similarity index 100% rename from gems/activefunction-controller/bin/setup rename to bin/setup diff --git a/gems/activefunction-controller/gemfiles/rbs.gemfile b/gemfiles/rbs.gemfile similarity index 100% rename from gems/activefunction-controller/gemfiles/rbs.gemfile rename to gemfiles/rbs.gemfile diff --git a/gems/activefunction-controller/gemfiles/rubocop.gemfile b/gemfiles/rubocop.gemfile similarity index 100% rename from gems/activefunction-controller/gemfiles/rubocop.gemfile rename to gemfiles/rubocop.gemfile diff --git a/gems/activefunction-controller/CODE_OF_CONDUCT.md b/gems/activefunction-controller/CODE_OF_CONDUCT.md deleted file mode 100644 index c7280d2..0000000 --- a/gems/activefunction-controller/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,84 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. - -We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. - -## Our Standards - -Examples of behavior that contributes to a positive environment for our community include: - -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience -* Focusing on what is best not just for us as individuals, but for the overall community - -Examples of unacceptable behavior include: - -* The use of sexualized language or imagery, and sexual attention or - advances of any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email - address, without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Enforcement Responsibilities - -Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. - -Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. - -## Scope - -This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at danil.maximov@flatstack.com. All complaints will be reviewed and investigated promptly and fairly. - -All community leaders are obligated to respect the privacy and security of the reporter of any incident. - -## Enforcement Guidelines - -Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: - -### 1. Correction - -**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. - -**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. - -### 2. Warning - -**Community Impact**: A violation through a single incident or series of actions. - -**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. - -### 3. Temporary Ban - -**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. - -**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. - -### 4. Permanent Ban - -**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. - -**Consequence**: A permanent ban from any sort of public interaction within the community. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, -available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. - -Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). - -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see the FAQ at -https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. diff --git a/gems/activefunction-controller/lib/.rbnext/2.7/active_function_controller/strong_parameters.rb b/gems/activefunction-controller/lib/.rbnext/2.7/active_function_controller/strong_parameters.rb deleted file mode 100644 index 19443a4..0000000 --- a/gems/activefunction-controller/lib/.rbnext/2.7/active_function_controller/strong_parameters.rb +++ /dev/null @@ -1,102 +0,0 @@ -# frozen_string_literal: true - -require "forwardable" - -module ActiveFunction::Controller - class ParameterMissingError < Error - MESSAGE_TEMPLATE = "Missing parameter: %s" - - attr_reader :message - - def initialize(param) - MESSAGE_TEMPLATE % param - end - end - - class UnpermittedParameterError < Error - MESSAGE_TEMPLATE = "Unpermitted parameter: %s" - - attr_reader :message - - def initialize(param) - MESSAGE_TEMPLATE % param - end - end - - module StrongParameters - def params - @_params ||= Parameters.new(@request) - end - - class Parameters - extend Forwardable - def_delegators :@parameters, :each, :map - include Enumerable - - def initialize(parameters, permitted: false) - @parameters = parameters - @permitted = permitted - end - - def [](attribute) - nested_attribute(parameters[attribute]) - end - - def require(attribute) - value = self[attribute] - - raise ParameterMissingError, attribute if value.nil? - - value - end - - def permit(*attributes) - pparams = {} - - attributes.each do |attribute| - if attribute.is_a? Hash - attribute.each do |k, v| - pparams[k] = process_nested(self[k], :permit, v) - end - else - next unless parameters.key?(attribute) - - pparams[attribute] = self[attribute] - end - end - - Parameters.new(pparams, permitted: true) - end - - def to_h - raise UnpermittedParameterError, parameters.keys unless @permitted - - parameters.transform_values { |_1| process_nested(_1, :to_h) } - end - - private - - def nested_attribute(attribute) - if attribute.is_a? Hash - Parameters.new(attribute) - elsif attribute.is_a?(Array) && attribute[0].is_a?(Hash) - attribute.map { |_1| Parameters.new(_1) } - else - attribute - end - end - - def process_nested(attribute, method, options = []) - if attribute.is_a? Parameters - attribute.send(method, *options) - elsif attribute.is_a?(Array) && attribute[0].is_a?(Parameters) - attribute.map { |_1| _1.send(method, *options) } - else - attribute - end - end - - attr_reader :parameters - end - end -end diff --git a/gems/activefunction-controller/lib/.rbnext/3.0/active_function_controller/core.rb b/gems/activefunction-controller/lib/.rbnext/3.0/active_function_controller/core.rb deleted file mode 100644 index afb9402..0000000 --- a/gems/activefunction-controller/lib/.rbnext/3.0/active_function_controller/core.rb +++ /dev/null @@ -1,47 +0,0 @@ -# frozen_string_literal: true - -module ActiveFunction::Controller - class MissingRouteMethod < Error - MESSAGE_TEMPLATE = "Missing function route: %s" - - attr_reader :message - - def initialize(context) - @message = MESSAGE_TEMPLATE % context - end - end - - class NotRenderedError < Error - MESSAGE_TEMPLATE = "render was not called: %s" - - attr_reader :message - - def initialize(context) - @message = MESSAGE_TEMPLATE % context - end - end - - module Core - attr_reader :action_name, :request, :response - - def dispatch(action_name, request, response) - @action_name = action_name - @request = request - @response = response - - raise MissingRouteMethod, @action_name unless respond_to?(action_name) - - process(@action_name) - - raise NotRenderedError, @action_name unless performed? - - @response.to_h - end - - private - - def process(action) ; public_send(action); end - - def performed? ; @response.committed?; end - end -end diff --git a/gems/activefunction-controller/lib/.rbnext/3.0/active_function_controller/response.rb b/gems/activefunction-controller/lib/.rbnext/3.0/active_function_controller/response.rb deleted file mode 100644 index 17e164a..0000000 --- a/gems/activefunction-controller/lib/.rbnext/3.0/active_function_controller/response.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -module ActiveFunction::Controller - class Response - attr_accessor :status, :headers, :body - - def initialize(status: 200, headers: {}, body: nil) - @status = status - @headers = headers - @body = body - @committed = false - end - - def to_h - { - statusCode: status, - headers: headers, - body: body - } - end - - def commit! - @committed = true - end - - def committed? ; @committed; end - end -end diff --git a/gems/activefunction-controller/lib/active_function_controller.rb b/gems/activefunction-controller/lib/active_function_controller.rb deleted file mode 100644 index d900be7..0000000 --- a/gems/activefunction-controller/lib/active_function_controller.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -require_relative "active_function_controller/version" - -module ActiveFunction - module Controller - class Error < StandardError; end - - class Base - require_relative "active_function_controller/core" - require_relative "active_function_controller/callbacks" - require_relative "active_function_controller/strong_parameters" - require_relative "active_function_controller/rendering" - require_relative "active_function_controller/response" - - include Core - include Callbacks - include Rendering - include StrongParameters - - def self.process(action_name, request = {}, response = Response.new) - new.dispatch(action_name, request, response) - end - end - end -end diff --git a/gems/activefunction-controller/lib/active_function_controller/callbacks.rb b/gems/activefunction-controller/lib/active_function_controller/callbacks.rb deleted file mode 100644 index 3eecdea..0000000 --- a/gems/activefunction-controller/lib/active_function_controller/callbacks.rb +++ /dev/null @@ -1,67 +0,0 @@ -# frozen_string_literal: true - -module ActiveFunction::Controller - class MissingCallbackContext < Error - MESSAGE_TEMPLATE = "Missing callback context: %s" - - attr_reader :message - - def initialize(context) - @message = MESSAGE_TEMPLATE % context - end - end - - module Callbacks - def self.included(base) - base.extend(ClassMethods) - end - - private - - def process(*) - _run_callbacks :before - - super - - _run_callbacks :after - end - - def _run_callbacks(type) - self.class.callbacks[type].each do |callback_method, options| - raise MissingCallbackContext, callback_method unless respond_to?(callback_method, true) - - send(callback_method) if _executable?(options) - end - end - - def _executable?(options) - return false if options[:only] && !options[:only].include?(@action_name) - return false if options[:if] && !send(options[:if]) - true - end - - module ClassMethods - def inherited(subclass) - subclass.instance_variable_set(:@__callbacks, @__callbacks) - end - - def before_action(method, options = {}) - set_callback :before, method, options - end - - def after_action(method, options = {}) - set_callback :after, method, options - end - - def set_callback(type, method, options = {}) - callbacks[type][method] = options - end - - def callbacks - @__callbacks ||= {before: {}, after: {}} - - @__callbacks - end - end - end -end diff --git a/gems/activefunction-controller/lib/active_function_controller/core.rb b/gems/activefunction-controller/lib/active_function_controller/core.rb deleted file mode 100644 index 57c1719..0000000 --- a/gems/activefunction-controller/lib/active_function_controller/core.rb +++ /dev/null @@ -1,47 +0,0 @@ -# frozen_string_literal: true - -module ActiveFunction::Controller - class MissingRouteMethod < Error - MESSAGE_TEMPLATE = "Missing function route: %s" - - attr_reader :message - - def initialize(context) - @message = MESSAGE_TEMPLATE % context - end - end - - class NotRenderedError < Error - MESSAGE_TEMPLATE = "render was not called: %s" - - attr_reader :message - - def initialize(context) - @message = MESSAGE_TEMPLATE % context - end - end - - module Core - attr_reader :action_name, :request, :response - - def dispatch(action_name, request, response) - @action_name = action_name - @request = request - @response = response - - raise MissingRouteMethod, @action_name unless respond_to?(action_name) - - process(@action_name) - - raise NotRenderedError, @action_name unless performed? - - @response.to_h - end - - private - - def process(action) = public_send(action) - - def performed? = @response.committed? - end -end diff --git a/gems/activefunction-controller/lib/active_function_controller/rendering.rb b/gems/activefunction-controller/lib/active_function_controller/rendering.rb deleted file mode 100644 index ae22195..0000000 --- a/gems/activefunction-controller/lib/active_function_controller/rendering.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -require "json" - -module ActiveFunction::Controller - class DoubleRenderError < Error - MESSAGE_TEMPLATE = "#render was called multiple times in action: %s" - - attr_reader :message - - def initialize(context) - @message = MESSAGE_TEMPLATE % context - end - end - - module Rendering - DEFAULT_HEADER = {"Content-Type" => "application/json"}.freeze - - def render(status: 200, json: {}, head: {}) - raise DoubleRenderError, @action_name if performed? - - @response.status = status - @response.headers = head.merge(Hash[DEFAULT_HEADER]) - @response.body = JSON.generate(json) - - @response.commit! - end - end -end diff --git a/gems/activefunction-controller/lib/active_function_controller/response.rb b/gems/activefunction-controller/lib/active_function_controller/response.rb deleted file mode 100644 index c5ff701..0000000 --- a/gems/activefunction-controller/lib/active_function_controller/response.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -module ActiveFunction::Controller - class Response - attr_accessor :status, :headers, :body - - def initialize(status: 200, headers: {}, body: nil) - @status = status - @headers = headers - @body = body - @committed = false - end - - def to_h - { - statusCode: status, - headers: headers, - body: body - } - end - - def commit! - @committed = true - end - - def committed? = @committed - end -end diff --git a/gems/activefunction-controller/lib/active_function_controller/strong_parameters.rb b/gems/activefunction-controller/lib/active_function_controller/strong_parameters.rb deleted file mode 100644 index 97364c5..0000000 --- a/gems/activefunction-controller/lib/active_function_controller/strong_parameters.rb +++ /dev/null @@ -1,102 +0,0 @@ -# frozen_string_literal: true - -require "forwardable" - -module ActiveFunction::Controller - class ParameterMissingError < Error - MESSAGE_TEMPLATE = "Missing parameter: %s" - - attr_reader :message - - def initialize(param) - MESSAGE_TEMPLATE % param - end - end - - class UnpermittedParameterError < Error - MESSAGE_TEMPLATE = "Unpermitted parameter: %s" - - attr_reader :message - - def initialize(param) - MESSAGE_TEMPLATE % param - end - end - - module StrongParameters - def params - @_params ||= Parameters.new(@request) - end - - class Parameters - extend Forwardable - def_delegators :@parameters, :each, :map - include Enumerable - - def initialize(parameters, permitted: false) - @parameters = parameters - @permitted = permitted - end - - def [](attribute) - nested_attribute(parameters[attribute]) - end - - def require(attribute) - value = self[attribute] - - raise ParameterMissingError, attribute if value.nil? - - value - end - - def permit(*attributes) - pparams = {} - - attributes.each do |attribute| - if attribute.is_a? Hash - attribute.each do |k, v| - pparams[k] = process_nested(self[k], :permit, v) - end - else - next unless parameters.key?(attribute) - - pparams[attribute] = self[attribute] - end - end - - Parameters.new(pparams, permitted: true) - end - - def to_h - raise UnpermittedParameterError, parameters.keys unless @permitted - - parameters.transform_values { process_nested(_1, :to_h) } - end - - private - - def nested_attribute(attribute) - if attribute.is_a? Hash - Parameters.new(attribute) - elsif attribute.is_a?(Array) && attribute[0].is_a?(Hash) - attribute.map { Parameters.new(_1) } - else - attribute - end - end - - def process_nested(attribute, method, options = []) - if attribute.is_a? Parameters - attribute.send(method, *options) - elsif attribute.is_a?(Array) && attribute[0].is_a?(Parameters) - attribute.map { _1.send(method, *options) } - else - attribute - end - end - - attr_reader :parameters - end - end -end diff --git a/gems/activefunction-controller/sig/active_function_controller.rbs b/gems/activefunction-controller/sig/active_function_controller.rbs deleted file mode 100644 index 9f36002..0000000 --- a/gems/activefunction-controller/sig/active_function_controller.rbs +++ /dev/null @@ -1,19 +0,0 @@ -module ActiveFunction - module Controller - class Error < StandardError - end - - type hash = Hash[untyped, untyped] - - interface _Controller - def performed?: -> bool - end - - class Base - extend Controller::Callbacks::ClassMethods - - def self.new: -> Controller::Core - def self.process: (Symbol action_name, ?hash request, ?Controller::Response response) -> Controller::Response::responseHash - end - end -end diff --git a/gems/activefunction-controller/sig/active_function_controller/rendering.rbs b/gems/activefunction-controller/sig/active_function_controller/rendering.rbs deleted file mode 100644 index 1689f9d..0000000 --- a/gems/activefunction-controller/sig/active_function_controller/rendering.rbs +++ /dev/null @@ -1,18 +0,0 @@ -module ActiveFunction::Controller - class DoubleRenderError < Error - MESSAGE_TEMPLATE: String - - attr_reader message: String - - def initialize: (String context) -> void - end - - module Rendering : Core - include _Controller - - DEFAULT_HEADER: Hash[String, String] - @performed: bool - - def render: (?status: ::Integer, ?json: hash, ?head: hash) -> void - end -end diff --git a/lib/.rbnext/2.7/active_function/functions/strong_parameters.rb b/lib/.rbnext/2.7/active_function/functions/strong_parameters.rb new file mode 100644 index 0000000..728e392 --- /dev/null +++ b/lib/.rbnext/2.7/active_function/functions/strong_parameters.rb @@ -0,0 +1,104 @@ +# frozen_string_literal: true + +require "forwardable" + +module ActiveFunction + class ParameterMissingError < Error + MESSAGE_TEMPLATE = "Missing parameter: %s" + + attr_reader :message + + def initialize(param) + MESSAGE_TEMPLATE % param + end + end + + class UnpermittedParameterError < Error + MESSAGE_TEMPLATE = "Unpermitted parameter: %s" + + attr_reader :message + + def initialize(param) + MESSAGE_TEMPLATE % param + end + end + + module Functions + module StrongParameters + def params + @_params ||= Parameters.new(@request) + end + + class Parameters + extend Forwardable + def_delegators :@parameters, :each, :map + include Enumerable + + def initialize(parameters, permitted: false) + @parameters = parameters + @permitted = permitted + end + + def [](attribute) + nested_attribute(parameters[attribute]) + end + + def require(attribute) + value = self[attribute] + + raise ParameterMissingError, attribute if value.nil? + + value + end + + def permit(*attributes) + pparams = {} + + attributes.each do |attribute| + if attribute.is_a? Hash + attribute.each do |k, v| + pparams[k] = process_nested(self[k], :permit, v) + end + else + next unless parameters.key?(attribute) + + pparams[attribute] = self[attribute] + end + end + + Parameters.new(pparams, permitted: true) + end + + def to_h + raise UnpermittedParameterError, parameters.keys unless @permitted + + parameters.transform_values { |_1| process_nested(_1, :to_h) } + end + + private + + def nested_attribute(attribute) + if attribute.is_a? Hash + Parameters.new(attribute) + elsif attribute.is_a?(Array) && attribute[0].is_a?(Hash) + attribute.map { |_1| Parameters.new(_1) } + else + attribute + end + end + + def process_nested(attribute, method, options = []) + if attribute.is_a? Parameters + attribute.send(method, *options) + elsif attribute.is_a?(Array) && attribute[0].is_a?(Parameters) + attribute.map { |_1| _1.send(method, *options) } + else + attribute + end + end + + attr_reader :parameters + end + end + end +end diff --git a/lib/.rbnext/3.0/active_function/functions/core.rb b/lib/.rbnext/3.0/active_function/functions/core.rb new file mode 100644 index 0000000..1130069 --- /dev/null +++ b/lib/.rbnext/3.0/active_function/functions/core.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +module ActiveFunction + class MissingRouteMethod < Error + MESSAGE_TEMPLATE = "Missing function route: %s" + + attr_reader :message + + def initialize(context) + @message = MESSAGE_TEMPLATE % context + end + end + + class NotRenderedError < Error + MESSAGE_TEMPLATE = "render was not called: %s" + + attr_reader :message + + def initialize(context) + @message = MESSAGE_TEMPLATE % context + end + end + + module Functions + module Core + attr_reader :action_name, :request, :response + + def dispatch(action_name, request, response) + @action_name = action_name + @request = request + @response = response + + raise MissingRouteMethod, @action_name unless respond_to?(action_name) + + process(@action_name) + + raise NotRenderedError, @action_name unless performed? + + @response.to_h + end + + private + + def process(action) ; public_send(action); end + + def performed? ; @response.committed?; end + end + end +end diff --git a/lib/.rbnext/3.0/active_function/functions/response.rb b/lib/.rbnext/3.0/active_function/functions/response.rb new file mode 100644 index 0000000..4a67340 --- /dev/null +++ b/lib/.rbnext/3.0/active_function/functions/response.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module ActiveFunction + module Functions + class Response + attr_accessor :status, :headers, :body + + def initialize(status: 200, headers: {}, body: nil) + @status = status + @headers = headers + @body = body + @committed = false + end + + def to_h + { + statusCode: status, + headers: headers, + body: body + } + end + + def commit! + @committed = true + end + + def committed? ; @committed; end + end + end +end diff --git a/gems/activefunction-core/lib/active_function_core.rb b/lib/active_function.rb similarity index 74% rename from gems/activefunction-core/lib/active_function_core.rb rename to lib/active_function.rb index 8b92927..3c7a1bc 100644 --- a/gems/activefunction-core/lib/active_function_core.rb +++ b/lib/active_function.rb @@ -8,5 +8,6 @@ module ActiveFunction class Error < StandardError; end - require "active_function_core/version" + require "active_function/version" + require "active_function/base" end diff --git a/lib/active_function/base.rb b/lib/active_function/base.rb new file mode 100644 index 0000000..5fc9b70 --- /dev/null +++ b/lib/active_function/base.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module ActiveFunction + class Base + require "active_function/functions/core" + require "active_function/functions/callbacks" + require "active_function/functions/strong_parameters" + require "active_function/functions/rendering" + require "active_function/functions/response" + + include Functions::Core + include Functions::Callbacks + include Functions::Rendering + include Functions::StrongParameters + + def self.process(action_name, request = {}, response = Functions::Response.new) + new.dispatch(action_name, request, response) + end + end +end diff --git a/lib/active_function/functions/callbacks.rb b/lib/active_function/functions/callbacks.rb new file mode 100644 index 0000000..d43e021 --- /dev/null +++ b/lib/active_function/functions/callbacks.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +module ActiveFunction + class MissingCallbackContext < Error + MESSAGE_TEMPLATE = "Missing callback context: %s" + + attr_reader :message + + def initialize(context) + @message = MESSAGE_TEMPLATE % context + end + end + + module Functions + module Callbacks + def self.included(base) + base.extend(ClassMethods) + end + + private + + def process(*) + _run_callbacks :before + + super + + _run_callbacks :after + end + + def _run_callbacks(type) + self.class.callbacks[type].each do |callback_method, options| + raise MissingCallbackContext, callback_method unless respond_to?(callback_method, true) + + send(callback_method) if _executable?(options) + end + end + + def _executable?(options) + return false if options[:only] && !options[:only].include?(@action_name) + return false if options[:if] && !send(options[:if]) + true + end + + module ClassMethods + def inherited(subclass) + subclass.instance_variable_set(:@__callbacks, @__callbacks) + end + + def before_action(method, options = {}) + set_callback :before, method, options + end + + def after_action(method, options = {}) + set_callback :after, method, options + end + + def set_callback(type, method, options = {}) + callbacks[type][method] = options + end + + def callbacks + @__callbacks ||= {before: {}, after: {}} + + @__callbacks + end + end + end + end +end diff --git a/lib/active_function/functions/core.rb b/lib/active_function/functions/core.rb new file mode 100644 index 0000000..1db2a20 --- /dev/null +++ b/lib/active_function/functions/core.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +module ActiveFunction + class MissingRouteMethod < Error + MESSAGE_TEMPLATE = "Missing function route: %s" + + attr_reader :message + + def initialize(context) + @message = MESSAGE_TEMPLATE % context + end + end + + class NotRenderedError < Error + MESSAGE_TEMPLATE = "render was not called: %s" + + attr_reader :message + + def initialize(context) + @message = MESSAGE_TEMPLATE % context + end + end + + module Functions + module Core + attr_reader :action_name, :request, :response + + def dispatch(action_name, request, response) + @action_name = action_name + @request = request + @response = response + + raise MissingRouteMethod, @action_name unless respond_to?(action_name) + + process(@action_name) + + raise NotRenderedError, @action_name unless performed? + + @response.to_h + end + + private + + def process(action) = public_send(action) + + def performed? = @response.committed? + end + end +end diff --git a/lib/active_function/functions/rendering.rb b/lib/active_function/functions/rendering.rb new file mode 100644 index 0000000..b9f3edc --- /dev/null +++ b/lib/active_function/functions/rendering.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require "json" + +module ActiveFunction + class DoubleRenderError < Error + MESSAGE_TEMPLATE = "#render was called multiple times in action: %s" + + attr_reader :message + + def initialize(context) + @message = MESSAGE_TEMPLATE % context + end + end + + module Functions + module Rendering + DEFAULT_HEADER = {"Content-Type" => "application/json"}.freeze + + def render(status: 200, json: {}, head: {}) + raise DoubleRenderError, @action_name if performed? + + @response.status = status + @response.headers = head.merge(Hash[DEFAULT_HEADER]) + @response.body = JSON.generate(json) + + @response.commit! + end + end + end +end diff --git a/lib/active_function/functions/response.rb b/lib/active_function/functions/response.rb new file mode 100644 index 0000000..1c18c0e --- /dev/null +++ b/lib/active_function/functions/response.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module ActiveFunction + module Functions + class Response + attr_accessor :status, :headers, :body + + def initialize(status: 200, headers: {}, body: nil) + @status = status + @headers = headers + @body = body + @committed = false + end + + def to_h + { + statusCode: status, + headers: headers, + body: body + } + end + + def commit! + @committed = true + end + + def committed? = @committed + end + end +end diff --git a/lib/active_function/functions/strong_parameters.rb b/lib/active_function/functions/strong_parameters.rb new file mode 100644 index 0000000..097e21d --- /dev/null +++ b/lib/active_function/functions/strong_parameters.rb @@ -0,0 +1,104 @@ +# frozen_string_literal: true + +require "forwardable" + +module ActiveFunction + class ParameterMissingError < Error + MESSAGE_TEMPLATE = "Missing parameter: %s" + + attr_reader :message + + def initialize(param) + MESSAGE_TEMPLATE % param + end + end + + class UnpermittedParameterError < Error + MESSAGE_TEMPLATE = "Unpermitted parameter: %s" + + attr_reader :message + + def initialize(param) + MESSAGE_TEMPLATE % param + end + end + + module Functions + module StrongParameters + def params + @_params ||= Parameters.new(@request) + end + + class Parameters + extend Forwardable + def_delegators :@parameters, :each, :map + include Enumerable + + def initialize(parameters, permitted: false) + @parameters = parameters + @permitted = permitted + end + + def [](attribute) + nested_attribute(parameters[attribute]) + end + + def require(attribute) + value = self[attribute] + + raise ParameterMissingError, attribute if value.nil? + + value + end + + def permit(*attributes) + pparams = {} + + attributes.each do |attribute| + if attribute.is_a? Hash + attribute.each do |k, v| + pparams[k] = process_nested(self[k], :permit, v) + end + else + next unless parameters.key?(attribute) + + pparams[attribute] = self[attribute] + end + end + + Parameters.new(pparams, permitted: true) + end + + def to_h + raise UnpermittedParameterError, parameters.keys unless @permitted + + parameters.transform_values { process_nested(_1, :to_h) } + end + + private + + def nested_attribute(attribute) + if attribute.is_a? Hash + Parameters.new(attribute) + elsif attribute.is_a?(Array) && attribute[0].is_a?(Hash) + attribute.map { Parameters.new(_1) } + else + attribute + end + end + + def process_nested(attribute, method, options = []) + if attribute.is_a? Parameters + attribute.send(method, *options) + elsif attribute.is_a?(Array) && attribute[0].is_a?(Parameters) + attribute.map { _1.send(method, *options) } + else + attribute + end + end + + attr_reader :parameters + end + end + end +end diff --git a/gems/activefunction-controller/lib/active_function_controller/version.rb b/lib/active_function/version.rb similarity index 54% rename from gems/activefunction-controller/lib/active_function_controller/version.rb rename to lib/active_function/version.rb index d0a8c9f..0f9f88d 100644 --- a/gems/activefunction-controller/lib/active_function_controller/version.rb +++ b/lib/active_function/version.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true module ActiveFunction - module Controller - VERSION = "0.3.4" - end + VERSION = "0.3.4" end diff --git a/sig/active_function.rbs b/sig/active_function.rbs new file mode 100644 index 0000000..9c7ebfe --- /dev/null +++ b/sig/active_function.rbs @@ -0,0 +1,4 @@ +module ActiveFunction + class Error < StandardError + end +end diff --git a/sig/active_function/base.rbs b/sig/active_function/base.rbs new file mode 100644 index 0000000..58b6623 --- /dev/null +++ b/sig/active_function/base.rbs @@ -0,0 +1,14 @@ +module ActiveFunction + type hash = Hash[untyped, untyped] + + interface _Function + def performed?: -> bool + end + + class Base + extend Functions::Callbacks::ClassMethods + + def self.new: -> Functions::Core + def self.process: (Symbol action_name, ?hash request, ?Functions::Response response) -> Functions::Response::responseHash + end +end diff --git a/gems/activefunction-controller/sig/active_function_controller/callbacks.rbs b/sig/active_function/functions/callbacks.rbs similarity index 93% rename from gems/activefunction-controller/sig/active_function_controller/callbacks.rbs rename to sig/active_function/functions/callbacks.rbs index 24735c6..2c284d1 100644 --- a/gems/activefunction-controller/sig/active_function_controller/callbacks.rbs +++ b/sig/active_function/functions/callbacks.rbs @@ -1,4 +1,4 @@ -module ActiveFunction::Controller +module ActiveFunction class MissingCallbackContext < Error MESSAGE_TEMPLATE: String @@ -7,12 +7,13 @@ module ActiveFunction::Controller def initialize: (untyped context) -> void end + module Functions module Callbacks : Base, Core interface _Callbacks def callbacks: () -> Hash[Symbol, hash] end - include _Controller + include _Function extend _Callbacks type callbackType = :before | :after @@ -37,4 +38,5 @@ module ActiveFunction::Controller def self.included: (singleton(Base) base) -> void end + end end diff --git a/gems/activefunction-controller/sig/active_function_controller/core.rbs b/sig/active_function/functions/core.rbs similarity index 89% rename from gems/activefunction-controller/sig/active_function_controller/core.rbs rename to sig/active_function/functions/core.rbs index ebede51..3d77e2a 100644 --- a/gems/activefunction-controller/sig/active_function_controller/core.rbs +++ b/sig/active_function/functions/core.rbs @@ -1,4 +1,4 @@ -module ActiveFunction::Controller +module ActiveFunction class MissingRouteMethod < Error MESSAGE_TEMPLATE: String @@ -15,9 +15,9 @@ module ActiveFunction::Controller def initialize: (String context) -> void end - + module Functions module Core : Base - include _Controller + include _Function @performed: bool @action_name: Symbol @@ -30,4 +30,5 @@ module ActiveFunction::Controller def process: (Symbol action) -> void end + end end diff --git a/sig/active_function/functions/rendering.rbs b/sig/active_function/functions/rendering.rbs new file mode 100644 index 0000000..07e5c20 --- /dev/null +++ b/sig/active_function/functions/rendering.rbs @@ -0,0 +1,20 @@ +module ActiveFunction + class DoubleRenderError < Error + MESSAGE_TEMPLATE: String + + attr_reader message: String + + def initialize: (untyped context) -> void + end + + module Functions + module Rendering : Core + include _Function + + DEFAULT_HEADER: Hash[String, String] + @performed: bool + + def render: (?status: ::Integer, ?json: hash, ?head: hash) -> void + end + end +end diff --git a/gems/activefunction-controller/sig/active_function_controller/response.rbs b/sig/active_function/functions/response.rbs similarity index 96% rename from gems/activefunction-controller/sig/active_function_controller/response.rbs rename to sig/active_function/functions/response.rbs index 6269227..f1086b4 100644 --- a/gems/activefunction-controller/sig/active_function_controller/response.rbs +++ b/sig/active_function/functions/response.rbs @@ -1,5 +1,5 @@ module ActiveFunction - module Controller + module Functions class Response type responseHash = {statusCode: Integer, body: String | nil, headers: Hash[String, String]} diff --git a/gems/activefunction-controller/sig/active_function_controller/strong_parameters.rbs b/sig/active_function/functions/strong_parameters.rbs similarity index 94% rename from gems/activefunction-controller/sig/active_function_controller/strong_parameters.rbs rename to sig/active_function/functions/strong_parameters.rbs index 300cb5a..7acf700 100644 --- a/gems/activefunction-controller/sig/active_function_controller/strong_parameters.rbs +++ b/sig/active_function/functions/strong_parameters.rbs @@ -1,4 +1,4 @@ -module ActiveFunction::Controller +module ActiveFunction class ParameterMissingError < Error MESSAGE_TEMPLATE: String @@ -14,8 +14,10 @@ module ActiveFunction::Controller def initialize: (untyped param) -> void end + + module Functions module StrongParameters : Core - include _Controller + include _Function @_params: Parameters @@ -43,4 +45,5 @@ module ActiveFunction::Controller attr_reader parameters: hash end end + end end diff --git a/sig/aws_events/apiGatewayAuthorizerEvent.rbs b/sig/aws_events/apiGatewayAuthorizerEvent.rbs new file mode 100644 index 0000000..254eb9f --- /dev/null +++ b/sig/aws_events/apiGatewayAuthorizerEvent.rbs @@ -0,0 +1,5 @@ +type apiGatewayAuthorizerEvent = { + type: String, + authorizationToken: String, + methodArn: String +} diff --git a/sig/aws_events/apiGatewayV2HTTPEvent.rbs b/sig/aws_events/apiGatewayV2HTTPEvent.rbs new file mode 100644 index 0000000..9ee3ab5 --- /dev/null +++ b/sig/aws_events/apiGatewayV2HTTPEvent.rbs @@ -0,0 +1,81 @@ +type apiGatewayV2HTTPEvent = { + version: String, + routeKey: String, + rawPath: String, + rawQueryString: String, + cookies: Array[String], + headers: Hash[Symbol, String], + queryStringParameters: Hash[Symbol, String], + pathParameters: Hash[Symbol, String], + requestContext: apiGatewayV2HTTPRequestContext, + stageVariables: Hash[Symbol, String], + body: String, + isBase64Encoded: bool +} + +type apiGatewayV2HTTPRequestContext = { + accountId: String, + apiId: String, + domainName: String, + domainPrefix: String, + requestId: String, + routeKey: String, + stage: String, + time: String, + timeEpoch: Integer, + authorizer: apiGatewayV2HTTPRequestContextAuthorizer, + http: apiGatewayV2HTTPRequestContextHTTP, + authentication: apiGatewayV2HTTPRequestContextAuthentication, +} + +type apiGatewayV2HTTPRequestContextAuthorizer = { + jwt: apiGatewayV2HTTPRequestContextAuthorizerJWT, + lambda: Hash[Symbol, String], + iam: apiGatewayV2HTTPRequestContextAuthorizerIAM, +} + +type apiGatewayV2HTTPRequestContextAuthorizerJWT = { + claims: Hash[Symbol, String], + scopes: Array[String], +} + + +type apiGatewayV2HTTPRequestContextAuthorizerIAM = { + accessKey: String, + accountId: String, + callerId: String, + cognitoIdentity: apiGatewayV2HTTPRequestContextAuthorizerIAMCognitoIdentity, + principalOrgId: String, + userId: String, + userArn: String, +} + +type apiGatewayV2HTTPRequestContextAuthorizerIAMCognitoIdentity = { + identityId: String, + identityPoolId: String, +} + +type apiGatewayV2HTTPRequestContextHTTP = { + method: String, + path: String, + protocol: String, + sourceIp: String, + userAgent: String, +} + +type apiGatewayV2HTTPRequestContextAuthentication = { + clientCerts: apiGatewayV2HTTPRequestContextAuthenticationClientCert +} + +type apiGatewayV2HTTPRequestContextAuthenticationClientCert = { + clientCertPem: String, + subjectDN: String, + issuerDN: String, + serialNumber: String, + validity: apiGatewayV2HTTPRequestContextAuthenticationClientCertValidity, +} + +type apiGatewayV2HTTPRequestContextAuthenticationClientCertValidity = { + notBefore: String, + notAfter: String, +} diff --git a/sig/aws_events/awsCongigEvent.rbs b/sig/aws_events/awsCongigEvent.rbs new file mode 100644 index 0000000..6781581 --- /dev/null +++ b/sig/aws_events/awsCongigEvent.rbs @@ -0,0 +1,12 @@ +type awsConfigEvent = { + accountId: String, + configRuleId: String, + configRuleName: String, + configRuleArn: String, + eventLeftScope: bool, + executionRoleArn: String, + invokingEvent: String, + resultToken: String, + ruleParameters: String, + version: String +} diff --git a/sig/aws_events/cloudWatchLogsEvent.rbs b/sig/aws_events/cloudWatchLogsEvent.rbs new file mode 100644 index 0000000..0faa8a9 --- /dev/null +++ b/sig/aws_events/cloudWatchLogsEvent.rbs @@ -0,0 +1,22 @@ +type cloudWatchLogsEvent = { + awslogs: cloudWatchLogsRawData +} + +type cloudWatchLogsRawData = { + data: string +} + +type cloudWatchLogsData = { + owner: String, + logGroup: String, + logStream: String, + subscriptionFilters: Array[String], + messageType: String, + logEvents: Array[cloudWatchLogEvent] +} + +type cloudWatchLogEvent = { + id: String, + timestamp: Integer, + message: String +} diff --git a/sig/aws_events/codeCommitEvent.rbs b/sig/aws_events/codeCommitEvent.rbs new file mode 100644 index 0000000..da37694 --- /dev/null +++ b/sig/aws_events/codeCommitEvent.rbs @@ -0,0 +1,25 @@ +type codeCommitEvent = { + Records: Array[codeCommitRecord] +} + +type codeCommitRecord = { + eventID: String, + eventVersion: String, + eventTime: String, + eventTriggerName: String, + eventPartNumber: Integer, + eventName: String, + eventTriggerConfigId: String, + eventSourceARN: String, + codeCommit: Array[codeCommitReference], + userIdentityARN: String, + eventSource: String, + awsRegion: String, + eventTotalParts: Integer, + customData: String, +} + +type codeCommitReference = { + ref: String, + commit: String +} \ No newline at end of file diff --git a/sig/aws_events/cognitoEvent.rbs b/sig/aws_events/cognitoEvent.rbs new file mode 100644 index 0000000..0f5468b --- /dev/null +++ b/sig/aws_events/cognitoEvent.rbs @@ -0,0 +1,15 @@ +type cognitoEvent = { + version: Integer, + eventType: String, + region: String, + identityPoolId: String, + identityId: String, + datasetName: String, + datasetRecords: Hash[Symbol, cognitoDatasetRecord] +} + +type cognitoDatasetRecord = { + oldValue: String, + newValue: String, + op: String, +} diff --git a/sig/aws_events/dynamoDBEvent.rbs b/sig/aws_events/dynamoDBEvent.rbs new file mode 100644 index 0000000..62d32f1 --- /dev/null +++ b/sig/aws_events/dynamoDBEvent.rbs @@ -0,0 +1,30 @@ +type dynamoDBEvent = { Records: Array[dynamoDBEventRecord] } +type dynamoDBEventRecord = { + eventID: String, + eventVersion: String, + eventName: String, + eventSource: String, + eventSourceARN: String, + awsRegion: String, + dynamodb: dynamoDBStreamRecord, +} +type dynamoDBStreamRecord = { + Keys: Hash[Symbol, attributeValue], + NewImage: Hash[Symbol, attributeValue], + OldImage: Hash[Symbol, attributeValue], + SequenceNumber: String, + SizeBytes: Integer, + StreamViewType: String +} +type attributeValue = { + B: String, + BOOL: bool, + BS: Array[String], + L: Array[attributeValue], + M: Hash[Symbol, attributeValue], + N: String, + NS: Array[String], + NULL: bool, + S: String, + SS: Array[String] +} diff --git a/sig/aws_events/kinesisEvent.rbs b/sig/aws_events/kinesisEvent.rbs new file mode 100644 index 0000000..f559d77 --- /dev/null +++ b/sig/aws_events/kinesisEvent.rbs @@ -0,0 +1,16 @@ +type kinesisEvent = { Records: Array[kinesisEventRecords] } +type kinesisEventRecords = { + eventID: String, + eventName: String, + eventSource: String, + eventSourceARN: String, + eventVersion: String, + invokeIdentityArn: String, + kinesis: kinesisEventRecord +} +type kinesisEventRecord = { + approximateArrivalTimestamp: Float, + data: String, + partitionKey: String, + sequenceNumber: String +} diff --git a/sig/aws_events/kinesisFirehoseEvent.rbs b/sig/aws_events/kinesisFirehoseEvent.rbs new file mode 100644 index 0000000..81b1c5a --- /dev/null +++ b/sig/aws_events/kinesisFirehoseEvent.rbs @@ -0,0 +1,19 @@ +type kinesisFirehoseEvent = { + invocationId: String, + deliveryStreamArn: String, + region: String, + records: Array[kinesisFirehoseRecord] +} +type kinesisFirehoseRecord = { + data: String, + recordId: String, + approximateArrivalTimestamp: Integer, + kinesisRecordMetadata: kinesisRecordMetadata +} +type kinesisRecordMetadata = { + shardId: String, + partitionKey: String, + approximateArrivalTimestamp: String, + sequenceNumber: String, + subsequenceNumber: Integer +} diff --git a/sig/aws_events/s3Event.rbs b/sig/aws_events/s3Event.rbs new file mode 100644 index 0000000..2be130e --- /dev/null +++ b/sig/aws_events/s3Event.rbs @@ -0,0 +1,31 @@ +type s3Event = { Records: Array[s3EventRecord] } +type s3EventRecord = { + eventVersion: String, + eventSource: String, + awsRegion: String, + eventTime: String, + eventName: String, + userIdentity: s3UserIdentity, + requestParameters: s3RequestParameters, + responseElements: Hash[String, String], + s3: s3Entity +} +type s3UserIdentity = { principalId: String } +type s3RequestParameters = { sourceIPAddress: String } +type s3Entity = { + schemaVersion: String, + configurationId: String, + bucket: s3Bucket, + object: s3Object +} +type s3Bucket = { + name: String, + ownerIdentity: s3UserIdentity, + arn: String +} +type s3Object = { + key: String, + size: Integer, + eTag: String, + sequencer: String +} diff --git a/sig/aws_events/sesEvent.rbs b/sig/aws_events/sesEvent.rbs new file mode 100644 index 0000000..55e00d4 --- /dev/null +++ b/sig/aws_events/sesEvent.rbs @@ -0,0 +1,59 @@ +type sesEvent = { + Records: Array[sesRecord] +} + +type sesRecord = { + eventVersion: String, + eventSource: String, + ses: simpleEmailService +} + +type simpleEmailService = { + mail: simpleEmailMessage, + receipt: simpleEmailReceipt +} + +type simpleEmailMessage = { + timestamp: String, + source: String, + messageId: String, + destination: Array[String], + headersTruncated: bool, + headers: Array[sesHeader], + commonHeaders: commonHeaders +} + +type sesHeader = { + name: String, + value: String +} + +type commonHeaders = { + from: Array[String], + to: Array[String], + date: String, + messageId: String, + subject: String +} + +type simpleEmailReceipt = { + recipients: Array[String], + timestamp: String, + spamVerdict: simpleEmailVerdict, + virusVerdict: simpleEmailVerdict, + spfVerdict: simpleEmailVerdict, + dkimVerdict: simpleEmailVerdict, + dmarcVerdict: simpleEmailVerdict, + processingTimeMillis: Integer, + action: simpleEmailAction, +} + +type simpleEmailVerdict = { + status: String +} + +type simpleEmailAction = { + type: String, + topicArn: String, + position: Integer +} diff --git a/sig/aws_events/snsEvent.rbs b/sig/aws_events/snsEvent.rbs new file mode 100644 index 0000000..fc0e8c7 --- /dev/null +++ b/sig/aws_events/snsEvent.rbs @@ -0,0 +1,25 @@ +type snsEvent = { Records: Array[snsEventRecords] } +type snsEventRecords = { + EventVersion: String, + EventSubscriptionArn: String, + EventSource: String, + Sns: snsEntity +} +type snsEntity = { + SignatureVersion: String, + Timestamp: String, + Signature: String, + SigningCertUrl: String, + MessageId: String, + Message: String, + MessageAttributes: Hash[Symbol, snsMessageAttributes], + Type: String, + UnsubscribeUrl: String, + TopicArn: String, + Subject: String +} +type snsMessageAttributes = { + Type: String, + Value: String +} + diff --git a/sig/aws_events/sqsEvent.rbs b/sig/aws_events/sqsEvent.rbs new file mode 100644 index 0000000..3e99052 --- /dev/null +++ b/sig/aws_events/sqsEvent.rbs @@ -0,0 +1,20 @@ +type sqsEvent = { Records: Array[sqsEventRecords] } +type sqsEventRecords = { + messageId: String, + receiptHandle: String, + body: String, + attributes: Hash[Symbol, String], + messageAttributes: Hash[Symbol, sqsMessageAttribute], + md5OfBody: String, + md50fMessageAttributes: String, + eventSource: String, + eventSourceARN: String, + awsRegion: String +} +type sqsMessageAttribute = { + stringValue: String, + binaryValue: String, + stringListValues: Array[String], + binaryListValues: Array[String], + dataType: String +} diff --git a/gems/activefunction-controller/sig/manifest.yml b/sig/manifest.yml similarity index 100% rename from gems/activefunction-controller/sig/manifest.yml rename to sig/manifest.yml diff --git a/gems/activefunction-controller/sig/typeprof.rb b/sig/typeprof.rb similarity index 87% rename from gems/activefunction-controller/sig/typeprof.rb rename to sig/typeprof.rb index 433db4e..18372f6 100644 --- a/gems/activefunction-controller/sig/typeprof.rb +++ b/sig/typeprof.rb @@ -2,7 +2,7 @@ require "active_function" -function = Class.new(ActiveFunction::Controller::Base) do +function = Class.new(ActiveFunction::Base) do before_action :action, only: :index, if: :condition? after_action :action, only: :index, if: :condition? diff --git a/gems/activefunction-controller/test/active_function_test.rb b/test/active_function_test.rb similarity index 89% rename from gems/activefunction-controller/test/active_function_test.rb rename to test/active_function_test.rb index 9c7757e..15887a9 100644 --- a/gems/activefunction-controller/test/active_function_test.rb +++ b/test/active_function_test.rb @@ -2,13 +2,13 @@ require "test_helper" -class TestFunction < ActiveFunction::Controller::Base +class TestFunction < ActiveFunction::Base def index render json: {a: 1, b: 2}, status: 201, head: {"X-Test" => "test"} end end -class TestFunctionWithCallbacks < ActiveFunction::Controller::Base +class TestFunctionWithCallbacks < ActiveFunction::Base before_action :set_first def index @@ -22,7 +22,7 @@ def set_first end end -class TestFunctionWithParameters < ActiveFunction::Controller::Base +class TestFunctionWithParameters < ActiveFunction::Base def index render json: params.require(:data).permit(:id, message: %i[text]).to_h end diff --git a/gems/activefunction-controller/test/fixtures/aws_events/api_gateway_http.json b/test/fixtures/aws_events/api_gateway_http.json similarity index 100% rename from gems/activefunction-controller/test/fixtures/aws_events/api_gateway_http.json rename to test/fixtures/aws_events/api_gateway_http.json diff --git a/gems/activefunction-controller/test/fixtures/aws_events/dynamodb.json b/test/fixtures/aws_events/dynamodb.json similarity index 100% rename from gems/activefunction-controller/test/fixtures/aws_events/dynamodb.json rename to test/fixtures/aws_events/dynamodb.json diff --git a/gems/activefunction-controller/test/functions/callbacks_test.rb b/test/functions/callbacks_test.rb similarity index 97% rename from gems/activefunction-controller/test/functions/callbacks_test.rb rename to test/functions/callbacks_test.rb index b16d4b6..79265d9 100644 --- a/gems/activefunction-controller/test/functions/callbacks_test.rb +++ b/test/functions/callbacks_test.rb @@ -3,8 +3,8 @@ require "test_helper" class CallbackTestFunction - include ActiveFunction::Controller::Core - include ActiveFunction::Controller::Callbacks + include ActiveFunction::Functions::Core + include ActiveFunction::Functions::Callbacks def index nil diff --git a/gems/activefunction-controller/test/functions/core_test.rb b/test/functions/core_test.rb similarity index 78% rename from gems/activefunction-controller/test/functions/core_test.rb rename to test/functions/core_test.rb index 78b31a9..c8b64ba 100644 --- a/gems/activefunction-controller/test/functions/core_test.rb +++ b/test/functions/core_test.rb @@ -3,7 +3,7 @@ require "test_helper" class CoreTestFunction - include ActiveFunction::Controller::Core + include ActiveFunction::Functions::Core def index nil @@ -27,13 +27,13 @@ def test_action_to_be_called end def test_dispatch_raises_error_if_route_is_not_defined - assert_raises ActiveFunction::Controller::MissingRouteMethod do + assert_raises ActiveFunction::MissingRouteMethod do @function.dispatch(:show, {}, response) end end def test_dispatch_raises_error_if_render_was_not_called - assert_raises ActiveFunction::Controller::NotRenderedError do + assert_raises ActiveFunction::NotRenderedError do @function.dispatch(:index, {}, response) end end diff --git a/gems/activefunction-controller/test/functions/rendering_test.rb b/test/functions/rendering_test.rb similarity index 84% rename from gems/activefunction-controller/test/functions/rendering_test.rb rename to test/functions/rendering_test.rb index e18a6da..6430f9f 100644 --- a/gems/activefunction-controller/test/functions/rendering_test.rb +++ b/test/functions/rendering_test.rb @@ -3,8 +3,8 @@ require "test_helper" class RenderingTestFunction - include ActiveFunction::Controller::Core - include ActiveFunction::Controller::Rendering + include ActiveFunction::Functions::Core + include ActiveFunction::Functions::Rendering def index render @@ -40,7 +40,7 @@ def setup end def test_double_render - assert_raises ActiveFunction::Controller::DoubleRenderError do + assert_raises ActiveFunction::DoubleRenderError do @function.dispatch(:index, {}, response) end end @@ -69,8 +69,8 @@ def test_render_custom_response end class NotRenderedTestFunction - include ActiveFunction::Controller::Core - include ActiveFunction::Controller::Rendering + include ActiveFunction::Functions::Core + include ActiveFunction::Functions::Rendering def index nil @@ -83,7 +83,7 @@ def setup end def test_not_rendered - assert_raises ActiveFunction::Controller::NotRenderedError do + assert_raises ActiveFunction::NotRenderedError do @function.dispatch(:index, {}, response) end end diff --git a/gems/activefunction-controller/test/functions/response_test.rb b/test/functions/response_test.rb similarity index 93% rename from gems/activefunction-controller/test/functions/response_test.rb rename to test/functions/response_test.rb index 0285cb5..05fc7c4 100644 --- a/gems/activefunction-controller/test/functions/response_test.rb +++ b/test/functions/response_test.rb @@ -4,7 +4,7 @@ class ResponseTest < Minitest::Test def setup - @response = ActiveFunction::Controller::Response.new + @response = ActiveFunction::Functions::Response.new end def test_status diff --git a/gems/activefunction-controller/test/functions/strong_parameters_test.rb b/test/functions/strong_parameters_test.rb similarity index 92% rename from gems/activefunction-controller/test/functions/strong_parameters_test.rb rename to test/functions/strong_parameters_test.rb index e7101c1..a0f563d 100644 --- a/gems/activefunction-controller/test/functions/strong_parameters_test.rb +++ b/test/functions/strong_parameters_test.rb @@ -3,8 +3,8 @@ require "test_helper" class StrongParametersFunction - include ActiveFunction::Controller::Core - include ActiveFunction::Controller::StrongParameters + include ActiveFunction::Functions::Core + include ActiveFunction::Functions::StrongParameters end class StrongParametersTest < Minitest::Test @@ -13,12 +13,12 @@ def setup end def test_params - assert_instance_of ActiveFunction::Controller::StrongParameters::Parameters, @function.params + assert_instance_of ActiveFunction::Functions::StrongParameters::Parameters, @function.params end end -describe ActiveFunction::Controller::StrongParameters::Parameters do - let(:described_class) { ::ActiveFunction::Controller::StrongParameters::Parameters } +describe ActiveFunction::Functions::StrongParameters::Parameters do + let(:described_class) { ::ActiveFunction::Functions::StrongParameters::Parameters } def assert_nested_params(expected, actual) assert_equal expected, actual.instance_variable_get(:@parameters) @@ -112,7 +112,7 @@ def assert_nested_params(expected, actual) it "raises a ParameterMissingError when the parameter does not exist" do params = described_class.new({}) - assert_raises(ActiveFunction::Controller::ParameterMissingError) { params.require(:name) } + assert_raises(ActiveFunction::ParameterMissingError) { params.require(:name) } end end @@ -194,7 +194,7 @@ def assert_nested_params(expected, actual) it "raises UnpermittedParameterError when some parameter is not permitted" do params = described_class.new({name: "Pupa"}) - assert_raises(ActiveFunction::Controller::UnpermittedParameterError) { params.to_h } + assert_raises(ActiveFunction::UnpermittedParameterError) { params.to_h } end end end diff --git a/gems/activefunction-controller/test/support/active_function_helper.rb b/test/support/active_function_helper.rb similarity index 80% rename from gems/activefunction-controller/test/support/active_function_helper.rb rename to test/support/active_function_helper.rb index 050fc3b..b706d8f 100644 --- a/gems/activefunction-controller/test/support/active_function_helper.rb +++ b/test/support/active_function_helper.rb @@ -2,7 +2,7 @@ module ActiveFunctionHelper def response - ActiveFunction::Controller::Response.new + ActiveFunction::Functions::Response.new end def committed_response diff --git a/gems/activefunction-controller/test/test_helper.rb b/test/test_helper.rb similarity index 88% rename from gems/activefunction-controller/test/test_helper.rb rename to test/test_helper.rb index 62cbc09..e2fc55e 100644 --- a/gems/activefunction-controller/test/test_helper.rb +++ b/test/test_helper.rb @@ -6,7 +6,7 @@ require "minitest/autorun" require "minitest/reporters" -require "active_function_controller" +require "active_function" require "./test/support/active_function_helper" From e7a3c96289af52ab71dd52186b7016183ee53961 Mon Sep 17 00:00:00 2001 From: Nerbyk Date: Sun, 20 Aug 2023 15:41:03 +0700 Subject: [PATCH 4/8] activefunction-core cleanup --- activefunction.gemspec | 3 +- .../.github/workflows/CI.yml | 44 ------------------- .../.github/workflows/lint.yml | 41 ----------------- gems/activefunction-core/.gitignore | 16 ------- gems/activefunction-core/.rbnextrc | 5 --- gems/activefunction-core/.rubocop.yml | 42 ------------------ gems/activefunction-core/Gemfile | 14 ------ gems/activefunction-core/LICENSE.txt | 21 +++++++++ gems/activefunction-core/Rakefile | 41 ----------------- ...re.gemspec => activefunction_core.gemspec} | 21 ++++----- gems/activefunction-core/bin/console | 15 ------- gems/activefunction-core/bin/rake | 27 ------------ gems/activefunction-core/bin/setup | 8 ---- gems/activefunction-core/gemfiles/rbs.gemfile | 4 -- .../gemfiles/rubocop.gemfile | 8 ---- .../lib/active_function_core.rb | 12 +++++ .../test/active_function_core_test.rb | 2 +- lib/active_function.rb | 5 +-- 18 files changed, 44 insertions(+), 285 deletions(-) delete mode 100644 gems/activefunction-core/.github/workflows/CI.yml delete mode 100644 gems/activefunction-core/.github/workflows/lint.yml delete mode 100644 gems/activefunction-core/.gitignore delete mode 100644 gems/activefunction-core/.rbnextrc delete mode 100644 gems/activefunction-core/.rubocop.yml delete mode 100644 gems/activefunction-core/Gemfile create mode 100644 gems/activefunction-core/LICENSE.txt delete mode 100644 gems/activefunction-core/Rakefile rename gems/activefunction-core/{active_function_core.gemspec => activefunction_core.gemspec} (50%) delete mode 100755 gems/activefunction-core/bin/console delete mode 100755 gems/activefunction-core/bin/rake delete mode 100755 gems/activefunction-core/bin/setup delete mode 100644 gems/activefunction-core/gemfiles/rbs.gemfile delete mode 100644 gems/activefunction-core/gemfiles/rubocop.gemfile create mode 100644 gems/activefunction-core/lib/active_function_core.rb diff --git a/activefunction.gemspec b/activefunction.gemspec index 896e90d..f8e18fa 100644 --- a/activefunction.gemspec +++ b/activefunction.gemspec @@ -35,9 +35,8 @@ Gem::Specification.new do |spec| spec.required_ruby_version = ">= 2.6" - spec.add_runtime_dependency "ruby-next-core", ">= 0.14.0" + spec.add_dependency "activefunction-core", "= 0.1.0" - spec.add_development_dependency "ruby-next", ">= 0.14.0" spec.add_development_dependency "rake", ">= 13.0" spec.add_development_dependency "minitest", "~> 5.15.0" spec.add_development_dependency "minitest-reporters", "~> 1.4.3" diff --git a/gems/activefunction-core/.github/workflows/CI.yml b/gems/activefunction-core/.github/workflows/CI.yml deleted file mode 100644 index 59d4530..0000000 --- a/gems/activefunction-core/.github/workflows/CI.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: CI Build - -on: - push: - branches: [ master ] - pull_request: - branches: [ '**' ] - -jobs: - minitest: - runs-on: ubuntu-latest - env: - BUNDLE_JOBS: 4 - BUNDLE_RETRY: 3 - BUNDLE_GEMFILE: "${{ matrix.gemfile }}" - CI: true - strategy: - fail-fast: false - matrix: - ruby: ["3.0"] - gemfile: [ - "Gemfile" - ] - rbs: [ 'false' ] - include: - - ruby: "3.1" - rbs: 'true' - gemfile: "Gemfile" - - ruby: "2.7" - rbs: 'false' - gemfile: "Gemfile" - steps: - - uses: actions/checkout@v2 - - uses: ruby/setup-ruby@v1 - with: - ruby-version: ${{ matrix.ruby }} - bundler-cache: true - bundler: 2.2.15 - - name: Run Ruby Next - run: bundle exec rake nextify - - name: Run MiniTest - run: bundle exec rake test - - diff --git a/gems/activefunction-core/.github/workflows/lint.yml b/gems/activefunction-core/.github/workflows/lint.yml deleted file mode 100644 index fb5e383..0000000 --- a/gems/activefunction-core/.github/workflows/lint.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Rubocop & Steep - -on: - push: - branches: - - master - pull_request: - -jobs: - rubocop: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: ruby/setup-ruby@v1 - with: - ruby-version: 2.7 - - name: Lint Ruby code with RuboCop - run: | - gem install bundler - bundle install --gemfile gemfiles/rubocop.gemfile --jobs 4 --retry 3 - bundle exec --gemfile gemfiles/rubocop.gemfile rubocop - steep: - runs-on: ubuntu-latest - env: - BUNDLE_JOBS: 4 - BUNDLE_RETRY: 3 - BUNDLE_FORCE_RUBY_PLATFORM: 1 - CI: true - strategy: - matrix: - ruby: ["3.0"] - steps: - - uses: actions/checkout@v2 - - uses: ruby/setup-ruby@v1 - with: - ruby-version: ${{ matrix.ruby }} - bundler-cache: true - bundler: 2.2.15 - - name: Run Steep - run: | - bundle exec rake steep \ No newline at end of file diff --git a/gems/activefunction-core/.gitignore b/gems/activefunction-core/.gitignore deleted file mode 100644 index fde9bf6..0000000 --- a/gems/activefunction-core/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -/.bundle/ -/.yardoc -/_yardoc/ -/coverage/ -/doc/ -/pkg/ -/spec/reports/ -/tmp/ - -gemfiles/*.lock - -Gemfile.lock -Gemfile.local -.rspec -.ruby-version -*.gem diff --git a/gems/activefunction-core/.rbnextrc b/gems/activefunction-core/.rbnextrc deleted file mode 100644 index 834894a..0000000 --- a/gems/activefunction-core/.rbnextrc +++ /dev/null @@ -1,5 +0,0 @@ -nextify: | - ./lib - --min-version=2.5 - --edge - --proposed diff --git a/gems/activefunction-core/.rubocop.yml b/gems/activefunction-core/.rubocop.yml deleted file mode 100644 index 644bc11..0000000 --- a/gems/activefunction-core/.rubocop.yml +++ /dev/null @@ -1,42 +0,0 @@ -require: - - standard/cop/block_single_line_braces - - ruby-next/rubocop - -inherit_gem: - standard: config/base.yml - -AllCops: - Exclude: - - 'bin/*' - - 'tmp/**/*' - - 'Gemfile' - - 'vendor/**/*' - - 'gemfiles/**/*' - - '*.gemspec' - DisplayCopNames: true - SuggestExtensions: false - TargetRubyVersion: next - -Standard/BlockSingleLineBraces: - Enabled: false - -Style/FrozenStringLiteralComment: - Enabled: true - -Style/HashConversion: - Enabled: false - -Naming/FileName: - Exclude: - - '**/*.md' - -# FIXME: Enable back when Ruby Next 0.14 is released -Layout/SpaceAfterColon: - Enabled: false - -Layout/ExtraSpacing: - ForceEqualSignAlignment: true - -Layout/HashAlignment: - EnforcedHashRocketStyle: table - EnforcedColonStyle: table diff --git a/gems/activefunction-core/Gemfile b/gems/activefunction-core/Gemfile deleted file mode 100644 index 198133c..0000000 --- a/gems/activefunction-core/Gemfile +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: true - -source "https://rubygems.org" - -gem 'pry-byebug', platform: :mri - -gemspec - -eval_gemfile "gemfiles/rubocop.gemfile" -eval_gemfile "gemfiles/rbs.gemfile" - -local_gemfile = "#{File.dirname(__FILE__)}/Gemfile.local" - -eval(File.read(local_gemfile)) if File.exist?(local_gemfile) # rubocop:disable Security/Eval diff --git a/gems/activefunction-core/LICENSE.txt b/gems/activefunction-core/LICENSE.txt new file mode 100644 index 0000000..2a2716b --- /dev/null +++ b/gems/activefunction-core/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2023 Nerbyk + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/gems/activefunction-core/Rakefile b/gems/activefunction-core/Rakefile deleted file mode 100644 index 07a3ea0..0000000 --- a/gems/activefunction-core/Rakefile +++ /dev/null @@ -1,41 +0,0 @@ -# frozen_string_literal: true - -require "bundler/gem_tasks" -require "rake/testtask" - -Rake::TestTask.new do |t| - t.libs << "test" - t.libs << "lib" - t.test_files = FileList["test/**/*_test.rb"] - t.warning = false - t.verbose = true -end - -begin - require "rubocop/rake_task" - RuboCop::RakeTask.new -rescue LoadError - task(:rubocop) {} -end - -RuboCop::RakeTask.new - -task :steep do - require "steep" - require "steep/cli" - - Steep::CLI.new(argv: ["check"], stdout: $stdout, stderr: $stderr, stdin: $stdin).run -end - -namespace :steep do - task :stats do - exec "bundle exec steep stats --log-level=fatal --format=table'" - end -end - -desc "Run Ruby Next nextify" -task :nextify do - sh "bundle exec ruby-next nextify -V" -end - -task default: %i[test rubocop steep] diff --git a/gems/activefunction-core/active_function_core.gemspec b/gems/activefunction-core/activefunction_core.gemspec similarity index 50% rename from gems/activefunction-core/active_function_core.gemspec rename to gems/activefunction-core/activefunction_core.gemspec index a1d519c..f487eff 100644 --- a/gems/activefunction-core/active_function_core.gemspec +++ b/gems/activefunction-core/activefunction_core.gemspec @@ -8,26 +8,21 @@ Gem::Specification.new do |spec| spec.authors = ["Nerbyk"] spec.email = ["danil.maximov2000@gmail.com"] - spec.summary = %(ActiveFunction::Core) - spec.description = %(Provides core functionality for ActiveFunction and ruby-next integration) - spec.homepage = "https://github.com/DanilMaximov/acitvefunction/gems/active_function-core" + spec.summary = %(ActiveFunction core gem) + spec.description = %(Provides core functionality, plugins and ruby-next integration for ActiveFunction) + spec.homepage = "https://github.com/DanilMaximov/acitvefunction/gems/activefunction-core" spec.license = "MIT" spec.metadata = { - "homepage_uri" => "https://github.com/DanilMaximov/activefunction/gems/active_function-core", - "source_code_uri" => "https://github.com/DanilMaximov/activefunction/gems/active_function-core", - "changelog_uri" => "https://github.com/DanilMaximov/activefunction/gems/active_function-core/CHANGELOG.md" + "homepage_uri" => "https://github.com/DanilMaximov/activefunction/gems/activefunction-core", + "source_code_uri" => "https://github.com/DanilMaximov/activefunction/gems/activefunction-core", + "changelog_uri" => "https://github.com/DanilMaximov/activefunction/gems/activefunction-core/CHANGELOG.md" } - spec.files = Dir.glob("lib/**/*") + Dir.glob("lib/.rbnext/**/*") + Dir.glob("bin/**/*") + %w[sig/active_function.rbs sig/manifest.yml] + %w[README.md LICENSE.txt CHANGELOG.md] + spec.files = Dir.glob("lib/**/*") + Dir.glob("lib/.rbnext/**/*") + Dir.glob("bin/**/*") + %w[sig/active_function_core.rbs sig/manifest.yml] + %w[README.md LICENSE.txt CHANGELOG.md] spec.require_paths = ["lib"] spec.required_ruby_version = ">= 2.6" - spec.add_runtime_dependency "ruby-next-core", ">= 0.14.0" - - spec.add_development_dependency "ruby-next", ">= 0.14.0" - spec.add_development_dependency "rake", ">= 13.0" - spec.add_development_dependency "minitest", "~> 5.15.0" - spec.add_development_dependency "minitest-reporters", "~> 1.4.3" + spec.add_runtime_dependency "ruby-next-core", ">= 0.15.3" end diff --git a/gems/activefunction-core/bin/console b/gems/activefunction-core/bin/console deleted file mode 100755 index 3b6ba05..0000000 --- a/gems/activefunction-core/bin/console +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -require "bundler/setup" -require "active_function" - -# You can add fixtures and/or initialization code here to make experimenting -# with your gem easier. You can also use a different console, if you like. - -# (If you use this, don't forget to add pry to your Gemfile!) -# require "pry" -# Pry.start - -require "irb" -IRB.start(__FILE__) diff --git a/gems/activefunction-core/bin/rake b/gems/activefunction-core/bin/rake deleted file mode 100755 index 51e10c4..0000000 --- a/gems/activefunction-core/bin/rake +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -# -# This file was generated by Bundler. -# -# The application 'rake' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) - -bundle_binstub = File.expand_path("bundle", __dir__) - -if File.file?(bundle_binstub) - if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ - load(bundle_binstub) - else - abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. -Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") - end -end - -require "rubygems" -require "bundler/setup" - -load Gem.bin_path("rake", "rake") diff --git a/gems/activefunction-core/bin/setup b/gems/activefunction-core/bin/setup deleted file mode 100755 index dce67d8..0000000 --- a/gems/activefunction-core/bin/setup +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail -IFS=$'\n\t' -set -vx - -bundle install - -# Do any other automated setup that you need to do here diff --git a/gems/activefunction-core/gemfiles/rbs.gemfile b/gems/activefunction-core/gemfiles/rbs.gemfile deleted file mode 100644 index 163251f..0000000 --- a/gems/activefunction-core/gemfiles/rbs.gemfile +++ /dev/null @@ -1,4 +0,0 @@ -source "https://rubygems.org" do - gem "rbs" - gem "steep", "~> 1.2" -end diff --git a/gems/activefunction-core/gemfiles/rubocop.gemfile b/gems/activefunction-core/gemfiles/rubocop.gemfile deleted file mode 100644 index 0bcb769..0000000 --- a/gems/activefunction-core/gemfiles/rubocop.gemfile +++ /dev/null @@ -1,8 +0,0 @@ -source "https://rubygems.org" do - gem "rubocop", "~> 1.29.0" - gem "rubocop-performance" - gem "rubocop-rake" - gem "rubocop-shopify" - gem "standard", "~> 1.12.1" - gem "ruby-next", ">= 0.12" -end diff --git a/gems/activefunction-core/lib/active_function_core.rb b/gems/activefunction-core/lib/active_function_core.rb new file mode 100644 index 0000000..3f70507 --- /dev/null +++ b/gems/activefunction-core/lib/active_function_core.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require "ruby-next" +require "ruby-next/language/setup" + +RubyNext::Language.setup_gem_load_path(transpile: true) + +module ActiveFunctionCore + class Error < StandardError; end + + require "active_function_core/version" +end diff --git a/gems/activefunction-core/test/active_function_core_test.rb b/gems/activefunction-core/test/active_function_core_test.rb index 4ed0c16..91a96bb 100644 --- a/gems/activefunction-core/test/active_function_core_test.rb +++ b/gems/activefunction-core/test/active_function_core_test.rb @@ -4,6 +4,6 @@ class ActiveFunctionCoreTest < Minitest::Test def test_that_it_has_a_version_number - refute_nil ::ActiveFunction::VERSION + refute_nil ::ActiveFunctionCore::VERSION end end diff --git a/lib/active_function.rb b/lib/active_function.rb index 3c7a1bc..3fe7d52 100644 --- a/lib/active_function.rb +++ b/lib/active_function.rb @@ -1,9 +1,6 @@ # frozen_string_literal: true -require "ruby-next" -require "ruby-next/language/setup" - -RubyNext::Language.setup_gem_load_path(transpile: true) +require "activefunction-core" module ActiveFunction class Error < StandardError; end From af448c49c5ac78deff5161a81425227b0f6a312f Mon Sep 17 00:00:00 2001 From: Nerbyk Date: Sun, 20 Aug 2023 17:17:23 +0700 Subject: [PATCH 5/8] Rakefile cleanup --- .github/workflows/CI.yml | 2 +- .github/workflows/lint.yml | 42 +++++++++++++-------------- .rbnextrc | 2 +- Rakefile | 42 ++++----------------------- tasks/gems.rake | 29 +++++++++++++++++++ tasks/test.rake | 58 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 116 insertions(+), 59 deletions(-) create mode 100644 tasks/gems.rake create mode 100644 tasks/test.rake diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 59d4530..01146c9 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -39,6 +39,6 @@ jobs: - name: Run Ruby Next run: bundle exec rake nextify - name: Run MiniTest - run: bundle exec rake test + run: bundle exec rake test:all diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index fb5e383..c6be38e 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -18,24 +18,24 @@ jobs: run: | gem install bundler bundle install --gemfile gemfiles/rubocop.gemfile --jobs 4 --retry 3 - bundle exec --gemfile gemfiles/rubocop.gemfile rubocop - steep: - runs-on: ubuntu-latest - env: - BUNDLE_JOBS: 4 - BUNDLE_RETRY: 3 - BUNDLE_FORCE_RUBY_PLATFORM: 1 - CI: true - strategy: - matrix: - ruby: ["3.0"] - steps: - - uses: actions/checkout@v2 - - uses: ruby/setup-ruby@v1 - with: - ruby-version: ${{ matrix.ruby }} - bundler-cache: true - bundler: 2.2.15 - - name: Run Steep - run: | - bundle exec rake steep \ No newline at end of file + bundle exec rake rubocop:all + # steep: + # runs-on: ubuntu-latest + # env: + # BUNDLE_JOBS: 4 + # BUNDLE_RETRY: 3 + # BUNDLE_FORCE_RUBY_PLATFORM: 1 + # CI: true + # strategy: + # matrix: + # ruby: ["3.0"] + # steps: + # - uses: actions/checkout@v2 + # - uses: ruby/setup-ruby@v1 + # with: + # ruby-version: ${{ matrix.ruby }} + # bundler-cache: true + # bundler: 2.2.15 + # - name: Run Steep + # run: | + # bundle exec rake steep \ No newline at end of file diff --git a/.rbnextrc b/.rbnextrc index 834894a..d4cb1e1 100644 --- a/.rbnextrc +++ b/.rbnextrc @@ -1,5 +1,5 @@ nextify: | ./lib - --min-version=2.5 + --min-version=2.6 --edge --proposed diff --git a/Rakefile b/Rakefile index 07a3ea0..5741acf 100644 --- a/Rakefile +++ b/Rakefile @@ -1,41 +1,11 @@ # frozen_string_literal: true -require "bundler/gem_tasks" -require "rake/testtask" +require "fileutils" -Rake::TestTask.new do |t| - t.libs << "test" - t.libs << "lib" - t.test_files = FileList["test/**/*_test.rb"] - t.warning = false - t.verbose = true -end - -begin - require "rubocop/rake_task" - RuboCop::RakeTask.new -rescue LoadError - task(:rubocop) {} -end - -RuboCop::RakeTask.new - -task :steep do - require "steep" - require "steep/cli" +REPO_ROOT = File.dirname(__FILE__) +GEMS_DIR = "#{REPO_ROOT}/gems" +GEMS_DIRS = (Dir.glob("#{GEMS_DIR}/*") + Dir.glob(REPO_ROOT)) - Steep::CLI.new(argv: ["check"], stdout: $stdout, stderr: $stderr, stdin: $stdin).run +Dir.glob("#{REPO_ROOT}/tasks/**/*.rake").each do |task_file| + load(task_file) end - -namespace :steep do - task :stats do - exec "bundle exec steep stats --log-level=fatal --format=table'" - end -end - -desc "Run Ruby Next nextify" -task :nextify do - sh "bundle exec ruby-next nextify -V" -end - -task default: %i[test rubocop steep] diff --git a/tasks/gems.rake b/tasks/gems.rake new file mode 100644 index 0000000..8805d70 --- /dev/null +++ b/tasks/gems.rake @@ -0,0 +1,29 @@ + +# frozen_string_literal: true + +desc 'Builds gems by name' +task 'gems:build', [:gem_name] do |_, args| + gem_name = args[:gem_name] + current_dir = FileUtils.pwd + + raise "Gem #{gem_name} not found" unless Dir.exist?("#{$GEMS_DIR}/#{gem_name}") + + Dir.chdir("#{$GEMS_DIR}/#{gem_name}") do + version = File.read('VERSION').strip + sh("gem build #{gem_name}.gemspec") + FileUtils.mv("#{gem_name}-#{version}.gem", current_dir) + end +end + +desc "Publish gem to rubygems.org" +task "gems:publish", [:gem_name] do |_, args| + gem_name = args[:gem_name] + current_dir = FileUtils.pwd + + raise "Gem #{gem_name} not found" unless Dir.exist?("#{$GEMS_DIR}/#{gem_name}") + + Dir.chdir("#{$GEMS_DIR}/#{gem_name}") do + version = File.read("VERSION").strip + sh("gem push #{gem_name}-#{version}.gem") + end +end diff --git a/tasks/test.rake b/tasks/test.rake new file mode 100644 index 0000000..b49312e --- /dev/null +++ b/tasks/test.rake @@ -0,0 +1,58 @@ +require "rake/testtask" +require "rubocop/rake_task" + + +def gem_name(dir) + File.basename(dir) +end + +GEMS_DIRS.each do |gem_dir| + Rake::TestTask.new("test_gem:#{gem_name(gem_dir)}") do |t| + t.libs << "#{gem_dir}/test" + t.libs << "#{gem_dir}/lib" + t.test_files = FileList["#{gem_dir}/test/**/*_test.rb"] + t.warning = false + t.verbose = true + end + + RuboCop::RakeTask.new("rubocop:#{gem_name(gem_dir)}") do |t| + t.patterns = ["#{gem_dir}/lib/**/*.rb", "#{gem_dir}/test/**/*.rb"] + end +end + +desc "Run All Tests in each gem" +task "test:all" do + GEMS_DIRS.each do |gem_dir| + Rake::Task["test_gem:#{gem_name(gem_dir)}"].invoke + end +end + +desc "Run Specs for single gem" +task "test:gem", [:gem_name] do |_, args| + Rake::Task["test_gem:#{gem_name(args[:gem_name])}"].invoke +end + +desc "Check Rubocop for all gems" +task "rubocop:all" do + GEMS_DIRS.each do |gem_dir| + Rake::Task["rubocop:#{gem_name(gem_dir)}"].invoke + end +end + +desc "Check Rubocop for single gem" +task "rubocop:gem", [:gem_name] do |_, args| + Rake::Task["rubocop:#{gem_name(args[:gem_name])}"].invoke +end + +desc "Check Ruby Next for all gems" +task "nextify:all" do + GEMS_DIRS.each do |gem_dir| + sh "bundle exec ruby-next nextify #{gem_dir} -V" + end +end + +desc "Check Ruby Next for single gem" +task "nextify:gem", [:gem_name] do |_, args| + sh "cd #{args[:gem_name]} && bundle exec ruby-next nextify -V" +end + From 66e23ad173eb506ba972b29b4ec8b74ec62277a3 Mon Sep 17 00:00:00 2001 From: Nerbyk Date: Sun, 20 Aug 2023 17:17:34 +0700 Subject: [PATCH 6/8] small fixes --- Gemfile | 1 + activefunction.gemspec | 2 +- gems/activefunction-core/CHANGELOG.md | 4 +++- ...tion_core.gemspec => activefunction-core.gemspec} | 12 ++++++------ .../lib/active_function_core/version.rb | 2 +- lib/active_function.rb | 2 +- 6 files changed, 13 insertions(+), 10 deletions(-) rename gems/activefunction-core/{activefunction_core.gemspec => activefunction-core.gemspec} (69%) diff --git a/Gemfile b/Gemfile index 198133c..1cf4ecb 100644 --- a/Gemfile +++ b/Gemfile @@ -3,6 +3,7 @@ source "https://rubygems.org" gem 'pry-byebug', platform: :mri +gem 'activefunction-core', path: './gems/activefunction-core' gemspec diff --git a/activefunction.gemspec b/activefunction.gemspec index f8e18fa..f68e344 100644 --- a/activefunction.gemspec +++ b/activefunction.gemspec @@ -35,7 +35,7 @@ Gem::Specification.new do |spec| spec.required_ruby_version = ">= 2.6" - spec.add_dependency "activefunction-core", "= 0.1.0" + spec.add_dependency "activefunction-core", ">= 0.1.0" spec.add_development_dependency "rake", ">= 13.0" spec.add_development_dependency "minitest", "~> 5.15.0" diff --git a/gems/activefunction-core/CHANGELOG.md b/gems/activefunction-core/CHANGELOG.md index 701cd4c..eb2314d 100644 --- a/gems/activefunction-core/CHANGELOG.md +++ b/gems/activefunction-core/CHANGELOG.md @@ -1 +1,3 @@ -## [Unreleased] +## [0.1.0] + +- Introduce ruby-next integration diff --git a/gems/activefunction-core/activefunction_core.gemspec b/gems/activefunction-core/activefunction-core.gemspec similarity index 69% rename from gems/activefunction-core/activefunction_core.gemspec rename to gems/activefunction-core/activefunction-core.gemspec index f487eff..8d0ddde 100644 --- a/gems/activefunction-core/activefunction_core.gemspec +++ b/gems/activefunction-core/activefunction-core.gemspec @@ -3,22 +3,22 @@ require_relative "lib/active_function_core/version" Gem::Specification.new do |spec| - spec.name = "active_function_core" + spec.name = "activefunction-core" spec.version = ActiveFunction::VERSION spec.authors = ["Nerbyk"] spec.email = ["danil.maximov2000@gmail.com"] spec.summary = %(ActiveFunction core gem) spec.description = %(Provides core functionality, plugins and ruby-next integration for ActiveFunction) - spec.homepage = "https://github.com/DanilMaximov/acitvefunction/gems/activefunction-core" + spec.homepage = "https://github.com/DanilMaximov/activefunction" spec.license = "MIT" spec.metadata = { - "homepage_uri" => "https://github.com/DanilMaximov/activefunction/gems/activefunction-core", - "source_code_uri" => "https://github.com/DanilMaximov/activefunction/gems/activefunction-core", - "changelog_uri" => "https://github.com/DanilMaximov/activefunction/gems/activefunction-core/CHANGELOG.md" + "homepage_uri" => "https://github.com/DanilMaximov/activefunction-core", + "source_code_uri" => "https://github.com/DanilMaximov/activefunction-core", + "changelog_uri" => "https://github.com/DanilMaximov/activefunction-core/CHANGELOG.md" } - spec.files = Dir.glob("lib/**/*") + Dir.glob("lib/.rbnext/**/*") + Dir.glob("bin/**/*") + %w[sig/active_function_core.rbs sig/manifest.yml] + %w[README.md LICENSE.txt CHANGELOG.md] + spec.files = Dir.glob("lib/**/*") + Dir.glob("lib/.rbnext/**/*") + %w[sig/active_function_core.rbs sig/manifest.yml] + %w[README.md LICENSE.txt CHANGELOG.md] spec.require_paths = ["lib"] diff --git a/gems/activefunction-core/lib/active_function_core/version.rb b/gems/activefunction-core/lib/active_function_core/version.rb index 070cf1f..2fe03e4 100644 --- a/gems/activefunction-core/lib/active_function_core/version.rb +++ b/gems/activefunction-core/lib/active_function_core/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -module ActiveFunction +module ActiveFunctionCore VERSION = "0.1.0" end diff --git a/lib/active_function.rb b/lib/active_function.rb index 3fe7d52..a824963 100644 --- a/lib/active_function.rb +++ b/lib/active_function.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require "activefunction-core" +require "active_function_core" module ActiveFunction class Error < StandardError; end From cb1ec17e16f902a350135fe99a13469570d3fc0c Mon Sep 17 00:00:00 2001 From: Nerbyk Date: Sun, 20 Aug 2023 17:48:17 +0700 Subject: [PATCH 7/8] Fix CI config & Add more ruby runtimes 2.6..3.2 --- .github/workflows/CI.yml | 44 ------------------- .github/workflows/build.yml | 31 +++++++++++++ .github/workflows/lint.yml | 41 ----------------- .github/workflows/rubocop.yml | 21 +++++++++ .rbnextrc | 1 - .rubocop.yml | 1 - Gemfile | 1 - activefunction.gemspec | 2 +- bin/ruby-next | 16 +++++++ gemfiles/rubocop.gemfile | 2 +- .../activefunction-core.gemspec | 12 ++--- .../lib/active_function_core.rb | 1 - .../lib/active_function_core/version.rb | 2 +- lib/active_function.rb | 2 + tasks/gems.rake | 13 ------ tasks/test.rake | 23 +++++++--- 16 files changed, 95 insertions(+), 118 deletions(-) delete mode 100644 .github/workflows/CI.yml create mode 100644 .github/workflows/build.yml delete mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/rubocop.yml create mode 100755 bin/ruby-next diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml deleted file mode 100644 index 01146c9..0000000 --- a/.github/workflows/CI.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: CI Build - -on: - push: - branches: [ master ] - pull_request: - branches: [ '**' ] - -jobs: - minitest: - runs-on: ubuntu-latest - env: - BUNDLE_JOBS: 4 - BUNDLE_RETRY: 3 - BUNDLE_GEMFILE: "${{ matrix.gemfile }}" - CI: true - strategy: - fail-fast: false - matrix: - ruby: ["3.0"] - gemfile: [ - "Gemfile" - ] - rbs: [ 'false' ] - include: - - ruby: "3.1" - rbs: 'true' - gemfile: "Gemfile" - - ruby: "2.7" - rbs: 'false' - gemfile: "Gemfile" - steps: - - uses: actions/checkout@v2 - - uses: ruby/setup-ruby@v1 - with: - ruby-version: ${{ matrix.ruby }} - bundler-cache: true - bundler: 2.2.15 - - name: Run Ruby Next - run: bundle exec rake nextify - - name: Run MiniTest - run: bundle exec rake test:all - - diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..07f9bbd --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,31 @@ +name: Build + +on: + push: + branches: + - master + pull_request: + workflow_dispatch: + +jobs: + test: + runs-on: ubuntu-latest + env: + BUNDLE_JOBS: 4 + BUNDLE_RETRY: 3 + strategy: + fail-fast: false + matrix: + ruby: [2.6, 2.7, 3.0, 3.1, 3.2] + steps: + - uses: actions/checkout@v2 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + - name: Run Ruby Next + run: | + bundle exec rake nextify:all + - name: Run Minitest tests + run: | + bundle exec rake test:all \ No newline at end of file diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index c6be38e..0000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Rubocop & Steep - -on: - push: - branches: - - master - pull_request: - -jobs: - rubocop: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: ruby/setup-ruby@v1 - with: - ruby-version: 2.7 - - name: Lint Ruby code with RuboCop - run: | - gem install bundler - bundle install --gemfile gemfiles/rubocop.gemfile --jobs 4 --retry 3 - bundle exec rake rubocop:all - # steep: - # runs-on: ubuntu-latest - # env: - # BUNDLE_JOBS: 4 - # BUNDLE_RETRY: 3 - # BUNDLE_FORCE_RUBY_PLATFORM: 1 - # CI: true - # strategy: - # matrix: - # ruby: ["3.0"] - # steps: - # - uses: actions/checkout@v2 - # - uses: ruby/setup-ruby@v1 - # with: - # ruby-version: ${{ matrix.ruby }} - # bundler-cache: true - # bundler: 2.2.15 - # - name: Run Steep - # run: | - # bundle exec rake steep \ No newline at end of file diff --git a/.github/workflows/rubocop.yml b/.github/workflows/rubocop.yml new file mode 100644 index 0000000..0368ebe --- /dev/null +++ b/.github/workflows/rubocop.yml @@ -0,0 +1,21 @@ +name: Lint Ruby + +on: + push: + branches: + - master + pull_request: + +jobs: + rubocop: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.2 + bundler: 2.2.15 + bundler-cache: true + - name: Lint Rubocop + run: | + bundle exec rake rubocop:all \ No newline at end of file diff --git a/.rbnextrc b/.rbnextrc index d4cb1e1..2a7c529 100644 --- a/.rbnextrc +++ b/.rbnextrc @@ -1,5 +1,4 @@ nextify: | - ./lib --min-version=2.6 --edge --proposed diff --git a/.rubocop.yml b/.rubocop.yml index 644bc11..af490c6 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -30,7 +30,6 @@ Naming/FileName: Exclude: - '**/*.md' -# FIXME: Enable back when Ruby Next 0.14 is released Layout/SpaceAfterColon: Enabled: false diff --git a/Gemfile b/Gemfile index 1cf4ecb..198133c 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,6 @@ source "https://rubygems.org" gem 'pry-byebug', platform: :mri -gem 'activefunction-core', path: './gems/activefunction-core' gemspec diff --git a/activefunction.gemspec b/activefunction.gemspec index f68e344..9da8fc7 100644 --- a/activefunction.gemspec +++ b/activefunction.gemspec @@ -35,7 +35,7 @@ Gem::Specification.new do |spec| spec.required_ruby_version = ">= 2.6" - spec.add_dependency "activefunction-core", ">= 0.1.0" + spec.add_dependency "activefunction-core", ">= 0.0.1" spec.add_development_dependency "rake", ">= 13.0" spec.add_development_dependency "minitest", "~> 5.15.0" diff --git a/bin/ruby-next b/bin/ruby-next new file mode 100755 index 0000000..b08b4da --- /dev/null +++ b/bin/ruby-next @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby + +lib_path = File.expand_path("../lib", __dir__) +$LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path) + +require "ruby-next/cli" + +begin + cli = RubyNext::CLI.new + cli.run(ARGV) +rescue => e + raise e if $DEBUG + STDERR.puts e.message + STDERR.puts e.backtrace.join("\n") if ENV["RUBY_NEXT_DEBUG"] == "1" + exit 1 +end diff --git a/gemfiles/rubocop.gemfile b/gemfiles/rubocop.gemfile index 0bcb769..42a942d 100644 --- a/gemfiles/rubocop.gemfile +++ b/gemfiles/rubocop.gemfile @@ -4,5 +4,5 @@ source "https://rubygems.org" do gem "rubocop-rake" gem "rubocop-shopify" gem "standard", "~> 1.12.1" - gem "ruby-next", ">= 0.12" + gem "ruby-next", ">= 0.15.3" end diff --git a/gems/activefunction-core/activefunction-core.gemspec b/gems/activefunction-core/activefunction-core.gemspec index 8d0ddde..0c30277 100644 --- a/gems/activefunction-core/activefunction-core.gemspec +++ b/gems/activefunction-core/activefunction-core.gemspec @@ -4,15 +4,15 @@ require_relative "lib/active_function_core/version" Gem::Specification.new do |spec| spec.name = "activefunction-core" - spec.version = ActiveFunction::VERSION + spec.version = ActiveFunctionCore::VERSION spec.authors = ["Nerbyk"] spec.email = ["danil.maximov2000@gmail.com"] - spec.summary = %(ActiveFunction core gem) + spec.summary = %(ActiveFunction core gem) spec.description = %(Provides core functionality, plugins and ruby-next integration for ActiveFunction) - spec.homepage = "https://github.com/DanilMaximov/activefunction" - spec.license = "MIT" - spec.metadata = { + spec.homepage = "https://github.com/DanilMaximov/activefunction" + spec.license = "MIT" + spec.metadata = { "homepage_uri" => "https://github.com/DanilMaximov/activefunction-core", "source_code_uri" => "https://github.com/DanilMaximov/activefunction-core", "changelog_uri" => "https://github.com/DanilMaximov/activefunction-core/CHANGELOG.md" @@ -24,5 +24,5 @@ Gem::Specification.new do |spec| spec.required_ruby_version = ">= 2.6" - spec.add_runtime_dependency "ruby-next-core", ">= 0.15.3" + spec.add_runtime_dependency 'ruby-next-core', '~> 0.15', '>= 0.15.3' end diff --git a/gems/activefunction-core/lib/active_function_core.rb b/gems/activefunction-core/lib/active_function_core.rb index 3f70507..17e19bb 100644 --- a/gems/activefunction-core/lib/active_function_core.rb +++ b/gems/activefunction-core/lib/active_function_core.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true -require "ruby-next" require "ruby-next/language/setup" RubyNext::Language.setup_gem_load_path(transpile: true) diff --git a/gems/activefunction-core/lib/active_function_core/version.rb b/gems/activefunction-core/lib/active_function_core/version.rb index 2fe03e4..a0825a4 100644 --- a/gems/activefunction-core/lib/active_function_core/version.rb +++ b/gems/activefunction-core/lib/active_function_core/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module ActiveFunctionCore - VERSION = "0.1.0" + VERSION = "0.0.1" end diff --git a/lib/active_function.rb b/lib/active_function.rb index a824963..84b474e 100644 --- a/lib/active_function.rb +++ b/lib/active_function.rb @@ -2,6 +2,8 @@ require "active_function_core" +RubyNext::Language.setup_gem_load_path(transpile: true) + module ActiveFunction class Error < StandardError; end diff --git a/tasks/gems.rake b/tasks/gems.rake index 8805d70..65779b8 100644 --- a/tasks/gems.rake +++ b/tasks/gems.rake @@ -14,16 +14,3 @@ task 'gems:build', [:gem_name] do |_, args| FileUtils.mv("#{gem_name}-#{version}.gem", current_dir) end end - -desc "Publish gem to rubygems.org" -task "gems:publish", [:gem_name] do |_, args| - gem_name = args[:gem_name] - current_dir = FileUtils.pwd - - raise "Gem #{gem_name} not found" unless Dir.exist?("#{$GEMS_DIR}/#{gem_name}") - - Dir.chdir("#{$GEMS_DIR}/#{gem_name}") do - version = File.read("VERSION").strip - sh("gem push #{gem_name}-#{version}.gem") - end -end diff --git a/tasks/test.rake b/tasks/test.rake index b49312e..3486fbb 100644 --- a/tasks/test.rake +++ b/tasks/test.rake @@ -1,11 +1,14 @@ require "rake/testtask" require "rubocop/rake_task" - def gem_name(dir) File.basename(dir) end +def with_all_gems(name = true, &block) + GEMS_DIRS.each { |gem_dir| yield name ? gem_name(gem_dir) : gem_dir } +end + GEMS_DIRS.each do |gem_dir| Rake::TestTask.new("test_gem:#{gem_name(gem_dir)}") do |t| t.libs << "#{gem_dir}/test" @@ -22,8 +25,8 @@ end desc "Run All Tests in each gem" task "test:all" do - GEMS_DIRS.each do |gem_dir| - Rake::Task["test_gem:#{gem_name(gem_dir)}"].invoke + with_all_gems do |name| + Rake::Task["test_gem:#{name}"].invoke end end @@ -34,8 +37,8 @@ end desc "Check Rubocop for all gems" task "rubocop:all" do - GEMS_DIRS.each do |gem_dir| - Rake::Task["rubocop:#{gem_name(gem_dir)}"].invoke + with_all_gems do |name| + Rake::Task["rubocop:#{name}"].invoke end end @@ -46,8 +49,8 @@ end desc "Check Ruby Next for all gems" task "nextify:all" do - GEMS_DIRS.each do |gem_dir| - sh "bundle exec ruby-next nextify #{gem_dir} -V" + with_all_gems(false) do |path| + sh "bundle exec ruby-next nextify #{path}/lib -V" end end @@ -56,3 +59,9 @@ task "nextify:gem", [:gem_name] do |_, args| sh "cd #{args[:gem_name]} && bundle exec ruby-next nextify -V" end +desc "Transpile all gems" +task "transpile:all" do + with_all_gems(false) do |path| + sh "bundle exec bin/ruby-next nextify --transpile-mode=rewrite #{path}/lib -V" + end +end From 9a22039668d8667a0085c362fadd6a01c2228613 Mon Sep 17 00:00:00 2001 From: Nerbyk Date: Sun, 20 Aug 2023 20:11:46 +0700 Subject: [PATCH 8/8] bump activefunction version & changelog --- CHANGELOG.md | 6 ++++++ lib/active_function/version.rb | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3d2b49..ae3f51b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,3 +41,9 @@ # [0.3.4] - 2023-05-02 - Fix RubyNext runtime integration + +# [0.3.5] - 2023-08-20 + +- Start gem restructuring for modularizaition +- Introduce `activefunction-core` gem with RubyNext integration + \ No newline at end of file diff --git a/lib/active_function/version.rb b/lib/active_function/version.rb index 0f9f88d..82d0d6b 100644 --- a/lib/active_function/version.rb +++ b/lib/active_function/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module ActiveFunction - VERSION = "0.3.4" + VERSION = "0.3.5" end