blacksheep 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +41 -0
- data/LICENSE.txt +21 -0
- data/README.md +39 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/blacksheep.gemspec +42 -0
- data/lib/blacksheep.rb +16 -0
- data/lib/blacksheep/action.rb +65 -0
- data/lib/blacksheep/action_decorator.rb +9 -0
- data/lib/blacksheep/decorators/default_error_handler.rb +94 -0
- data/lib/blacksheep/decorators/json_transformer.rb +126 -0
- data/lib/blacksheep/decorators/localizer.rb +30 -0
- data/lib/blacksheep/decorators/result_matcher.rb +44 -0
- data/lib/blacksheep/json_meta.rb +41 -0
- data/lib/blacksheep/json_result.rb +43 -0
- data/lib/blacksheep/version.rb +3 -0
- metadata +121 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA256:
         | 
| 3 | 
            +
              metadata.gz: 5e39f0b5524839016bc9a6811e51257f49a2d5f00cf42d3d9fe07ab01de6b602
         | 
| 4 | 
            +
              data.tar.gz: c0d169df550b722a11ffa2aaf7ea0ef5657f3c64ad5f7b8b6ac2c10419ba7ef0
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: 589637c6979dbaebe1756f95ebe0038a7b707059b4a809f56d1d6575bbd4b5e2f8822bb54815e93491f0517b22a71ccb06d690da05b5396ea30fbe6c9acabb59
         | 
| 7 | 
            +
              data.tar.gz: b12064a64112255dc2b75aacf1a3ff2245131c96ccd5a12a863242e5642c10d97096f19010981c97b53940a905988bffd04508d77f337846e24dded666e874de
         | 
    
        data/.gitignore
    ADDED
    
    
    
        data/.rspec
    ADDED
    
    
    
        data/.travis.yml
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/Gemfile.lock
    ADDED
    
    | @@ -0,0 +1,41 @@ | |
| 1 | 
            +
            PATH
         | 
| 2 | 
            +
              remote: .
         | 
| 3 | 
            +
              specs:
         | 
| 4 | 
            +
                blacksheep (0.1.0)
         | 
| 5 | 
            +
                  dry-matcher
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            GEM
         | 
| 8 | 
            +
              remote: https://rubygems.org/
         | 
| 9 | 
            +
              specs:
         | 
| 10 | 
            +
                concurrent-ruby (1.1.8)
         | 
| 11 | 
            +
                diff-lcs (1.4.4)
         | 
| 12 | 
            +
                dry-core (0.5.0)
         | 
| 13 | 
            +
                  concurrent-ruby (~> 1.0)
         | 
| 14 | 
            +
                dry-matcher (0.9.0)
         | 
| 15 | 
            +
                  dry-core (~> 0.4, >= 0.4.8)
         | 
| 16 | 
            +
                rake (10.5.0)
         | 
| 17 | 
            +
                rspec (3.10.0)
         | 
| 18 | 
            +
                  rspec-core (~> 3.10.0)
         | 
| 19 | 
            +
                  rspec-expectations (~> 3.10.0)
         | 
| 20 | 
            +
                  rspec-mocks (~> 3.10.0)
         | 
| 21 | 
            +
                rspec-core (3.10.1)
         | 
| 22 | 
            +
                  rspec-support (~> 3.10.0)
         | 
| 23 | 
            +
                rspec-expectations (3.10.1)
         | 
| 24 | 
            +
                  diff-lcs (>= 1.2.0, < 2.0)
         | 
| 25 | 
            +
                  rspec-support (~> 3.10.0)
         | 
| 26 | 
            +
                rspec-mocks (3.10.2)
         | 
| 27 | 
            +
                  diff-lcs (>= 1.2.0, < 2.0)
         | 
| 28 | 
            +
                  rspec-support (~> 3.10.0)
         | 
| 29 | 
            +
                rspec-support (3.10.2)
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            PLATFORMS
         | 
| 32 | 
            +
              ruby
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            DEPENDENCIES
         | 
| 35 | 
            +
              blacksheep!
         | 
| 36 | 
            +
              bundler (~> 1.17)
         | 
| 37 | 
            +
              rake (~> 10.0)
         | 
| 38 | 
            +
              rspec (~> 3.0)
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            BUNDLED WITH
         | 
| 41 | 
            +
               1.17.2
         | 
    
        data/LICENSE.txt
    ADDED
    
    | @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            The MIT License (MIT)
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Copyright (c) 2021 Martin Schweizer
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Permission is hereby granted, free of charge, to any person obtaining a copy
         | 
| 6 | 
            +
            of this software and associated documentation files (the "Software"), to deal
         | 
| 7 | 
            +
            in the Software without restriction, including without limitation the rights
         | 
| 8 | 
            +
            to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         | 
| 9 | 
            +
            copies of the Software, and to permit persons to whom the Software is
         | 
| 10 | 
            +
            furnished to do so, subject to the following conditions:
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            The above copyright notice and this permission notice shall be included in
         | 
| 13 | 
            +
            all copies or substantial portions of the Software.
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         | 
| 16 | 
            +
            IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         | 
| 17 | 
            +
            FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         | 
| 18 | 
            +
            AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         | 
| 19 | 
            +
            LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         | 
| 20 | 
            +
            OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
         | 
| 21 | 
            +
            THE SOFTWARE.
         | 
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,39 @@ | |
| 1 | 
            +
            # Blacksheep
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/blacksheep`. To experiment with that code, run `bin/console` for an interactive prompt.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            TODO: Delete this and the text above, and describe your gem
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            ## Installation
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            Add this line to your application's Gemfile:
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            ```ruby
         | 
| 12 | 
            +
            gem 'blacksheep'
         | 
| 13 | 
            +
            ```
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            And then execute:
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                $ bundle
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            Or install it yourself as:
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                $ gem install blacksheep
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            ## Usage
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            TODO: Write usage instructions here
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            ## Development
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            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 tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            ## Contributing
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            Bug reports and pull requests are welcome on GitHub at https://github.com/verticonaut/blacksheep.
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            ## License
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
         | 
    
        data/Rakefile
    ADDED
    
    
    
        data/bin/console
    ADDED
    
    | @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "bundler/setup"
         | 
| 4 | 
            +
            require "blacksheep"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            # You can add fixtures and/or initialization code here to make experimenting
         | 
| 7 | 
            +
            # with your gem easier. You can also use a different console, if you like.
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            # (If you use this, don't forget to add pry to your Gemfile!)
         | 
| 10 | 
            +
            # require "pry"
         | 
| 11 | 
            +
            # Pry.start
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            require "irb"
         | 
| 14 | 
            +
            IRB.start(__FILE__)
         | 
    
        data/bin/setup
    ADDED
    
    
    
        data/blacksheep.gemspec
    ADDED
    
    | @@ -0,0 +1,42 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
            lib = File.expand_path("../lib", __FILE__)
         | 
| 3 | 
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         | 
| 4 | 
            +
            require "blacksheep/version"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Gem::Specification.new do |spec|
         | 
| 7 | 
            +
              spec.name          = "blacksheep"
         | 
| 8 | 
            +
              spec.version       = Blacksheep::VERSION
         | 
| 9 | 
            +
              spec.authors       = ["Martin Schweizer"]
         | 
| 10 | 
            +
              spec.email         = ["martin.schweizer6@bluewin.ch"]
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              spec.summary       = %q{Support for API acrtions}
         | 
| 13 | 
            +
              spec.description   = %q{…includes errorhandling and json transformer}
         | 
| 14 | 
            +
              spec.homepage      = "http://verticonaut.me"
         | 
| 15 | 
            +
              spec.license       = "MIT"
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
         | 
| 18 | 
            +
              # to allow pushing to a single host or delete this section to allow pushing to any host.
         | 
| 19 | 
            +
              if spec.respond_to?(:metadata)
         | 
| 20 | 
            +
                spec.metadata["homepage_uri"] = spec.homepage
         | 
| 21 | 
            +
                # spec.metadata["source_code_uri"] = "Put your gem's public repo URL here."
         | 
| 22 | 
            +
                # spec.metadata["changelog_uri"] = "Put your gem's CHANGELOG.md URL here."
         | 
| 23 | 
            +
              else
         | 
| 24 | 
            +
                raise "RubyGems 2.0 or newer is required to protect against " \
         | 
| 25 | 
            +
                  "public gem pushes."
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              # Specify which files should be added to the gem when it is released.
         | 
| 29 | 
            +
              # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
         | 
| 30 | 
            +
              spec.files         = Dir.chdir(File.expand_path('..', __FILE__)) do
         | 
| 31 | 
            +
                `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
              spec.bindir        = "exe"
         | 
| 34 | 
            +
              spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
         | 
| 35 | 
            +
              spec.require_paths = ["lib"]
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              spec.add_dependency "dry-matcher"
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              spec.add_development_dependency "bundler", "~> 1.17"
         | 
| 40 | 
            +
              spec.add_development_dependency "rake", "~> 10.0"
         | 
| 41 | 
            +
              spec.add_development_dependency "rspec", "~> 3.0"
         | 
| 42 | 
            +
            end
         | 
    
        data/lib/blacksheep.rb
    ADDED
    
    | @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            require "blacksheep/version"
         | 
| 2 | 
            +
            require "blacksheep/json_meta"
         | 
| 3 | 
            +
            require "blacksheep/json_result"
         | 
| 4 | 
            +
            require "blacksheep/action_decorator"
         | 
| 5 | 
            +
            require "blacksheep/decorators/default_error_handler"
         | 
| 6 | 
            +
            require "blacksheep/decorators/json_transformer"
         | 
| 7 | 
            +
            require "blacksheep/decorators/result_matcher"
         | 
| 8 | 
            +
            require "blacksheep/action"
         | 
| 9 | 
            +
            require "blacksheep/version"
         | 
| 10 | 
            +
             | 
| 11 | 
            +
             | 
| 12 | 
            +
             | 
| 13 | 
            +
            module Blacksheep
         | 
| 14 | 
            +
              class Error < StandardError; end
         | 
| 15 | 
            +
              # Your code goes here...
         | 
| 16 | 
            +
            end
         | 
| @@ -0,0 +1,65 @@ | |
| 1 | 
            +
            module Blacksheep
         | 
| 2 | 
            +
              # Transoformes key in object structures in different caseing (snake_case, pascal_case cucrrently)
         | 
| 3 | 
            +
              #
         | 
| 4 | 
            +
              # @example
         | 
| 5 | 
            +
              #   params = {
         | 
| 6 | 
            +
              #     attr: 1,
         | 
| 7 | 
            +
              #     _case: 'camel'
         | 
| 8 | 
            +
              #   }
         | 
| 9 | 
            +
              #
         | 
| 10 | 
            +
              #   result_in_camel_case = Blacksheep::JsonTransformer.new(params).process_transformed do |converted_params_in_snake_case|
         | 
| 11 | 
            +
              #     do_something_with(converted_params_in_snake_case)
         | 
| 12 | 
            +
              #     #…
         | 
| 13 | 
            +
              #   end
         | 
| 14 | 
            +
              #
         | 
| 15 | 
            +
              #   …alternative
         | 
| 16 | 
            +
              #   transformer = Blacksheep::JsonTransformer.new(params)
         | 
| 17 | 
            +
              #   converted_params_in_snake_case = transformer.transformed_params
         | 
| 18 | 
            +
              #   ...
         | 
| 19 | 
            +
              #   result = do_something_with(converted_params_in_snake_case)
         | 
| 20 | 
            +
              #   result_in_camel_case = transformer.transform_result(result)
         | 
| 21 | 
            +
              #
         | 
| 22 | 
            +
              # @class Blacksheep::Action
         | 
| 23 | 
            +
              class Action
         | 
| 24 | 
            +
                attr_reader :params, :current_user, :options
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                class << self
         | 
| 27 | 
            +
                  def decorators
         | 
| 28 | 
            +
                    @@decorators ||= []
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  def add_decorator(decorator)
         | 
| 32 | 
            +
                    decorators << decorator
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  def new(*)
         | 
| 36 | 
            +
                    instance = super
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                    decorators.each do |decorator|
         | 
| 39 | 
            +
                      instance = decorator.new(instance)
         | 
| 40 | 
            +
                    end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                    instance
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def call(params, current_user: nil, **options)
         | 
| 47 | 
            +
                  @params = params
         | 
| 48 | 
            +
                  @current_user = current_user
         | 
| 49 | 
            +
                  @options = options
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                def perform(params, current_user: nil, **options, &block)
         | 
| 53 | 
            +
                  @params = params
         | 
| 54 | 
            +
                  @current_user = current_user
         | 
| 55 | 
            +
                  @options = options
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  block.call(params)
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                def json_result(json, status: :ok)
         | 
| 61 | 
            +
                  JsonResult.new(json, status)
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
              end
         | 
| 65 | 
            +
            end
         | 
| @@ -0,0 +1,94 @@ | |
| 1 | 
            +
            module Blacksheep
         | 
| 2 | 
            +
              module Decorators
         | 
| 3 | 
            +
                # @class Blacksheep::Decorators::DefaultErrorHandler
         | 
| 4 | 
            +
                class DefaultErrorHandler < ActionDecorator
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def call(*)
         | 
| 7 | 
            +
                    puts error_handler: "*" * 50
         | 
| 8 | 
            +
                    super
         | 
| 9 | 
            +
                  rescue => exception
         | 
| 10 | 
            +
                    handle(exception)
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def perform(*)
         | 
| 14 | 
            +
                    super
         | 
| 15 | 
            +
                  rescue => exception
         | 
| 16 | 
            +
                    handle(exception)
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def handle(exception)
         | 
| 20 | 
            +
                    json = status = nil
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    # case exception
         | 
| 23 | 
            +
                    #   when Exceptions::ValidationException
         | 
| 24 | 
            +
                    #     errors = []
         | 
| 25 | 
            +
                    #     exception.model.errors.each do |attribute, message|
         | 
| 26 | 
            +
                    #       errors << {
         | 
| 27 | 
            +
                    #         title:  "'#{attribute}' validation error",
         | 
| 28 | 
            +
                    #         detail: message,
         | 
| 29 | 
            +
                    #       }
         | 
| 30 | 
            +
                    #     end
         | 
| 31 | 
            +
                    #     json = {
         | 
| 32 | 
            +
                    #       errors: errors
         | 
| 33 | 
            +
                    #     }
         | 
| 34 | 
            +
                    #     status = :unprocessable_entity # 422
         | 
| 35 | 
            +
                    #   when Pundit::NotAuthorizedError
         | 
| 36 | 
            +
                    #     json = {
         | 
| 37 | 
            +
                    #       errors: [
         | 
| 38 | 
            +
                    #         pointer: {
         | 
| 39 | 
            +
                    #           source: not_authorized_pointer(exception)
         | 
| 40 | 
            +
                    #         },
         | 
| 41 | 
            +
                    #         title: "#{exception.class}",
         | 
| 42 | 
            +
                    #         detail: "#{exception.message}",
         | 
| 43 | 
            +
                    #       ]
         | 
| 44 | 
            +
                    #     }
         | 
| 45 | 
            +
                    #     status = :unauthorized # 401
         | 
| 46 | 
            +
                    #   when Exceptions::AuthenticationInvalid
         | 
| 47 | 
            +
                    #     json = {
         | 
| 48 | 
            +
                    #       errors: [
         | 
| 49 | 
            +
                    #         pointer: {
         | 
| 50 | 
            +
                    #           source: 'Secured Module'
         | 
| 51 | 
            +
                    #         },
         | 
| 52 | 
            +
                    #         title: "#{exception.class}",
         | 
| 53 | 
            +
                    #         detail: "#{exception.message}",
         | 
| 54 | 
            +
                    #       ]
         | 
| 55 | 
            +
                    #     }
         | 
| 56 | 
            +
                    #     status = :unauthorized # 401
         | 
| 57 | 
            +
                    #   else
         | 
| 58 | 
            +
                    #     json = {
         | 
| 59 | 
            +
                    #       errors: [
         | 
| 60 | 
            +
                    #         pointer: {
         | 
| 61 | 
            +
                    #           source: 'Internal'
         | 
| 62 | 
            +
                    #         },
         | 
| 63 | 
            +
                    #         title: "#{exception.class}",
         | 
| 64 | 
            +
                    #         detail: "#{exception.message}",
         | 
| 65 | 
            +
                    #       ]
         | 
| 66 | 
            +
                    #     }
         | 
| 67 | 
            +
                    #     status = :internal_server_error # 500
         | 
| 68 | 
            +
                    # end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                    json = {
         | 
| 71 | 
            +
                      errors: [
         | 
| 72 | 
            +
                        pointer: {
         | 
| 73 | 
            +
                          source: 'Internal'
         | 
| 74 | 
            +
                        },
         | 
| 75 | 
            +
                        title: "#{exception.class}",
         | 
| 76 | 
            +
                        detail: "#{exception.message}",
         | 
| 77 | 
            +
                      ]
         | 
| 78 | 
            +
                    }
         | 
| 79 | 
            +
                    status = :internal_server_error # 500
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                    JsonResult.new(json, status)
         | 
| 82 | 
            +
                  end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                  # def not_authorized_pointer(exception)
         | 
| 85 | 
            +
                  #   if exception.record
         | 
| 86 | 
            +
                  #     "#{record.class}.find #{record.id}"
         | 
| 87 | 
            +
                  #   else
         | 
| 88 | 
            +
                  #     exception.message
         | 
| 89 | 
            +
                  #   end
         | 
| 90 | 
            +
                  # end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
              end
         | 
| 94 | 
            +
            end
         | 
| @@ -0,0 +1,126 @@ | |
| 1 | 
            +
            module Blacksheep
         | 
| 2 | 
            +
              module Decorators
         | 
| 3 | 
            +
                # @class Blacksheep::Decorators::JsonTransformer
         | 
| 4 | 
            +
                class JsonTransformer < ActionDecorator
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  attr_reader :case, :params
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  def call(params, **options)
         | 
| 9 | 
            +
                    puts transformer: "*" * 50
         | 
| 10 | 
            +
                    detect_case(params)
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                    transformed_params = self.transformed_params(params)
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                    json = super(transformed_params, **options)
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                    transformed_json = transform_result(json)
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                    JsonResult.new(transformed_json, :ok)
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def perform(params, current_user: nil, **options, &block)
         | 
| 22 | 
            +
                    detect_case(params)
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                    transformed_params = self.transformed_params(params)
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    json = block.call(transformed_params)
         | 
| 27 | 
            +
                    transformed_json = transform_result(json)
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                    JsonResult.new(transformed_json, :ok)
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
             | 
| 33 | 
            +
                  #
         | 
| 34 | 
            +
                  # Transform the params in the instance into snake_case - if detected - from source.
         | 
| 35 | 
            +
                  #
         | 
| 36 | 
            +
                  # @return [Array, Hash] The params converted into snake_case
         | 
| 37 | 
            +
                  # @see #snakecase_keys
         | 
| 38 | 
            +
                  def transformed_params(params)
         | 
| 39 | 
            +
                    case @case
         | 
| 40 | 
            +
                      when 'snake', 'as_is'
         | 
| 41 | 
            +
                        params
         | 
| 42 | 
            +
                      when 'camel'
         | 
| 43 | 
            +
                        snakecase_keys(params)
         | 
| 44 | 
            +
                      else
         | 
| 45 | 
            +
                        raise Blackseep::Error, "unknown_case #{@case}"
         | 
| 46 | 
            +
                    end
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  #
         | 
| 50 | 
            +
                  # Transform the obj with key in snake_case to the source case.
         | 
| 51 | 
            +
                  # NOTE: leading underscored are preserved (e.g. _my_laptop => _myLaptop)
         | 
| 52 | 
            +
                  #
         | 
| 53 | 
            +
                  # @param obj [Array, Hash] A result structure
         | 
| 54 | 
            +
                  # @return [Array, Hash] The rsult structure with keys converted to source caseing
         | 
| 55 | 
            +
                  # @see #camelize_keys
         | 
| 56 | 
            +
                  def transform_result(obj)
         | 
| 57 | 
            +
                    case @case
         | 
| 58 | 
            +
                      when 'snake', 'as_is'
         | 
| 59 | 
            +
                        obj
         | 
| 60 | 
            +
                      when 'camel'
         | 
| 61 | 
            +
                        camelize_keys(obj)
         | 
| 62 | 
            +
                      else
         | 
| 63 | 
            +
                        raise Blackseep::Error, "unknown_case #{@case}"
         | 
| 64 | 
            +
                    end
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                  #
         | 
| 68 | 
            +
                  # Make all keys in the passed object snake_case
         | 
| 69 | 
            +
                  #
         | 
| 70 | 
            +
                  # @param obj [Array, Hash] …
         | 
| 71 | 
            +
                  # @return [Array, Hash] The source obj with kyes transformed into snake_case
         | 
| 72 | 
            +
                  def snakecase_keys(obj)
         | 
| 73 | 
            +
                    deep_transform_keys(obj) { |k| k.to_s.underscore.to_sym }.with_indifferent_access
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  #
         | 
| 77 | 
            +
                  # Camlize keys - but keep leading underscores
         | 
| 78 | 
            +
                  #
         | 
| 79 | 
            +
                  # @param obj [Array, hash] …
         | 
| 80 | 
            +
                  # @return [Array, Hash] The passed in obj with keys transferred to camel_case.
         | 
| 81 | 
            +
                  def camelize_keys(obj)
         | 
| 82 | 
            +
                    deep_transform_keys(obj) { |k|
         | 
| 83 | 
            +
                      key = k.to_s
         | 
| 84 | 
            +
                      match = key.match(/^(?<underscores>_*)(?<attribute>\w*)/)
         | 
| 85 | 
            +
                      converted = match[:attribute].camelize(:lower)
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                      match[:underscores].present? ? "#{match[:underscores]}#{converted}" : converted
         | 
| 88 | 
            +
                    }
         | 
| 89 | 
            +
                  end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                  private
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                  def detect_case(params)
         | 
| 94 | 
            +
                    @params ||= params
         | 
| 95 | 
            +
                    @case ||= params ? params.fetch(:_case, 'as_is').to_s : 'as_is'
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                    @case
         | 
| 98 | 
            +
                  end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                  #
         | 
| 101 | 
            +
                  # Deep transform the keys in the obj structure as descibed in the block passed
         | 
| 102 | 
            +
                  #
         | 
| 103 | 
            +
                  # @param obj [Array, Hash] …
         | 
| 104 | 
            +
                  # @yield key [String] A block transforming the key passed into
         | 
| 105 | 
            +
                  # @yield_param key [String, Symbol] The key to be transformed
         | 
| 106 | 
            +
                  # @yield_return [String] The transfomed key
         | 
| 107 | 
            +
                  # @return [Array, Hash] The obj structure with transformed keys.
         | 
| 108 | 
            +
                  def deep_transform_keys(obj, &block)
         | 
| 109 | 
            +
                    case obj
         | 
| 110 | 
            +
                      when  Hash, ActionController::Parameters
         | 
| 111 | 
            +
                        res = {}.with_indifferent_access
         | 
| 112 | 
            +
                        obj.each do |key, value|
         | 
| 113 | 
            +
                          res[yield(key)] = deep_transform_keys(value, &block)
         | 
| 114 | 
            +
                        end
         | 
| 115 | 
            +
                        res
         | 
| 116 | 
            +
                      when Array
         | 
| 117 | 
            +
                        obj.map{ |each| deep_transform_keys(each, &block) }
         | 
| 118 | 
            +
                      else
         | 
| 119 | 
            +
                        obj
         | 
| 120 | 
            +
                    end
         | 
| 121 | 
            +
                  end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
             | 
| 124 | 
            +
                end
         | 
| 125 | 
            +
              end
         | 
| 126 | 
            +
            end
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            module Blacksheep
         | 
| 2 | 
            +
              module Decorators
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                # @class Blacksheep::Decorators::Localozer
         | 
| 5 | 
            +
                class Localizer < ActionDecorator
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  def call(params, **)
         | 
| 8 | 
            +
                    if (locale = params[:_locale])
         | 
| 9 | 
            +
                      I18n.with_locale(locale) do
         | 
| 10 | 
            +
                        super
         | 
| 11 | 
            +
                      end
         | 
| 12 | 
            +
                    else
         | 
| 13 | 
            +
                      super
         | 
| 14 | 
            +
                    end
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def perform(params, **)
         | 
| 18 | 
            +
                    if (locale = params[:_locale])
         | 
| 19 | 
            +
                      I18n.with_locale(locale) do
         | 
| 20 | 
            +
                        super
         | 
| 21 | 
            +
                      end
         | 
| 22 | 
            +
                    else
         | 
| 23 | 
            +
                      super
         | 
| 24 | 
            +
                    end
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| @@ -0,0 +1,44 @@ | |
| 1 | 
            +
            require "dry-matcher"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Blacksheep
         | 
| 4 | 
            +
              module Decorators
         | 
| 5 | 
            +
                # @class Blacksheep::Decorators::ResultMatcher
         | 
| 6 | 
            +
                class ResultMatcher < ActionDecorator
         | 
| 7 | 
            +
                  Matcher = -> {
         | 
| 8 | 
            +
                    # Match `json_result` with status :ok for success
         | 
| 9 | 
            +
                    success_case = Dry::Matcher::Case.new do |json_result, _|
         | 
| 10 | 
            +
                      if json_result.success?
         | 
| 11 | 
            +
                        json_result
         | 
| 12 | 
            +
                      else
         | 
| 13 | 
            +
                        # this is a constant from dry/core/constants
         | 
| 14 | 
            +
                        Dry::Matcher::Undefined
         | 
| 15 | 
            +
                      end
         | 
| 16 | 
            +
                    end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                    # Match `json_result` with status not :ok` for failure - other status' can be distinguished
         | 
| 19 | 
            +
                    failure_case = Dry::Matcher::Case.new do |json_result, patterns|
         | 
| 20 | 
            +
                      if !json_result.success! && (patterns.empty? || patterns.include?(json_result.status))
         | 
| 21 | 
            +
                        value
         | 
| 22 | 
            +
                      else
         | 
| 23 | 
            +
                        Dry::Matcher::Undefined
         | 
| 24 | 
            +
                      end
         | 
| 25 | 
            +
                    end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    # Build the matcher
         | 
| 28 | 
            +
                    Dry::Matcher.new(success: success_case, failure: failure_case)
         | 
| 29 | 
            +
                  }.call
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  include Dry::Matcher.for(:call, with: Matcher)
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  def call(*)
         | 
| 34 | 
            +
                    puts matcher: "*" * 50
         | 
| 35 | 
            +
                    super
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  def perform(*)
         | 
| 39 | 
            +
                    raise Blackseep::Error, 'JsonResultMatcher does not support #perform'
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
            end
         | 
| @@ -0,0 +1,41 @@ | |
| 1 | 
            +
            module Blacksheep
         | 
| 2 | 
            +
              class JsonMeta
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                attr_reader :json
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                def initialize(json = {})
         | 
| 7 | 
            +
                  @json = json
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                class << self
         | 
| 11 | 
            +
                  def success(title: nil, detail: nil)
         | 
| 12 | 
            +
                    new.success(title: title, detail: detail)
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def success(title: nil, detail: nil)
         | 
| 17 | 
            +
                  result = {
         | 
| 18 | 
            +
                    success: true,
         | 
| 19 | 
            +
                  }
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  if title.present?
         | 
| 22 | 
            +
                    result[:title] = title
         | 
| 23 | 
            +
                  elsif detail.present?
         | 
| 24 | 
            +
                    result[:title] = 'Success'
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  result[:detail] = detail if detail.present?
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  json[:result] = result
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  self
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def as_json
         | 
| 35 | 
            +
                  {
         | 
| 36 | 
            +
                    jsonMeta: json
         | 
| 37 | 
            +
                  }
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
            end
         | 
| @@ -0,0 +1,43 @@ | |
| 1 | 
            +
            module Blacksheep
         | 
| 2 | 
            +
              class JsonResult
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                attr_reader :json, :status
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                def initialize(json, status)
         | 
| 7 | 
            +
                  @json = json
         | 
| 8 | 
            +
                  @status = status
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def set_json(value)
         | 
| 12 | 
            +
                  @json = value
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  self
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def set_status(value)
         | 
| 18 | 
            +
                  @status = value
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  self
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def success?
         | 
| 24 | 
            +
                  @status == :ok
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def render(json_wrap: 'data')
         | 
| 28 | 
            +
                  {
         | 
| 29 | 
            +
                    json:   wrap(json, json_wrap: json_wrap),
         | 
| 30 | 
            +
                    status: status
         | 
| 31 | 
            +
                  }
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                private
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def wrap(json, json_wrap:)
         | 
| 37 | 
            +
                  wrap = success? ? json_wrap : nil
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  wrap.present? ? { wrap => json } : json
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,121 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: blacksheep
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.1.0
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Martin Schweizer
         | 
| 8 | 
            +
            autorequire:
         | 
| 9 | 
            +
            bindir: exe
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2021-05-17 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: dry-matcher
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - ">="
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: '0'
         | 
| 20 | 
            +
              type: :runtime
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - ">="
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: '0'
         | 
| 27 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            +
              name: bundler
         | 
| 29 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 | 
            +
                requirements:
         | 
| 31 | 
            +
                - - "~>"
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            +
                    version: '1.17'
         | 
| 34 | 
            +
              type: :development
         | 
| 35 | 
            +
              prerelease: false
         | 
| 36 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 | 
            +
                requirements:
         | 
| 38 | 
            +
                - - "~>"
         | 
| 39 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            +
                    version: '1.17'
         | 
| 41 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 42 | 
            +
              name: rake
         | 
| 43 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 | 
            +
                requirements:
         | 
| 45 | 
            +
                - - "~>"
         | 
| 46 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            +
                    version: '10.0'
         | 
| 48 | 
            +
              type: :development
         | 
| 49 | 
            +
              prerelease: false
         | 
| 50 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 | 
            +
                requirements:
         | 
| 52 | 
            +
                - - "~>"
         | 
| 53 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            +
                    version: '10.0'
         | 
| 55 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 56 | 
            +
              name: rspec
         | 
| 57 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 | 
            +
                requirements:
         | 
| 59 | 
            +
                - - "~>"
         | 
| 60 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            +
                    version: '3.0'
         | 
| 62 | 
            +
              type: :development
         | 
| 63 | 
            +
              prerelease: false
         | 
| 64 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 | 
            +
                requirements:
         | 
| 66 | 
            +
                - - "~>"
         | 
| 67 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 68 | 
            +
                    version: '3.0'
         | 
| 69 | 
            +
            description: "…includes errorhandling and json transformer"
         | 
| 70 | 
            +
            email:
         | 
| 71 | 
            +
            - martin.schweizer6@bluewin.ch
         | 
| 72 | 
            +
            executables: []
         | 
| 73 | 
            +
            extensions: []
         | 
| 74 | 
            +
            extra_rdoc_files: []
         | 
| 75 | 
            +
            files:
         | 
| 76 | 
            +
            - ".gitignore"
         | 
| 77 | 
            +
            - ".rspec"
         | 
| 78 | 
            +
            - ".travis.yml"
         | 
| 79 | 
            +
            - Gemfile
         | 
| 80 | 
            +
            - Gemfile.lock
         | 
| 81 | 
            +
            - LICENSE.txt
         | 
| 82 | 
            +
            - README.md
         | 
| 83 | 
            +
            - Rakefile
         | 
| 84 | 
            +
            - bin/console
         | 
| 85 | 
            +
            - bin/setup
         | 
| 86 | 
            +
            - blacksheep.gemspec
         | 
| 87 | 
            +
            - lib/blacksheep.rb
         | 
| 88 | 
            +
            - lib/blacksheep/action.rb
         | 
| 89 | 
            +
            - lib/blacksheep/action_decorator.rb
         | 
| 90 | 
            +
            - lib/blacksheep/decorators/default_error_handler.rb
         | 
| 91 | 
            +
            - lib/blacksheep/decorators/json_transformer.rb
         | 
| 92 | 
            +
            - lib/blacksheep/decorators/localizer.rb
         | 
| 93 | 
            +
            - lib/blacksheep/decorators/result_matcher.rb
         | 
| 94 | 
            +
            - lib/blacksheep/json_meta.rb
         | 
| 95 | 
            +
            - lib/blacksheep/json_result.rb
         | 
| 96 | 
            +
            - lib/blacksheep/version.rb
         | 
| 97 | 
            +
            homepage: http://verticonaut.me
         | 
| 98 | 
            +
            licenses:
         | 
| 99 | 
            +
            - MIT
         | 
| 100 | 
            +
            metadata:
         | 
| 101 | 
            +
              homepage_uri: http://verticonaut.me
         | 
| 102 | 
            +
            post_install_message:
         | 
| 103 | 
            +
            rdoc_options: []
         | 
| 104 | 
            +
            require_paths:
         | 
| 105 | 
            +
            - lib
         | 
| 106 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 107 | 
            +
              requirements:
         | 
| 108 | 
            +
              - - ">="
         | 
| 109 | 
            +
                - !ruby/object:Gem::Version
         | 
| 110 | 
            +
                  version: '0'
         | 
| 111 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 112 | 
            +
              requirements:
         | 
| 113 | 
            +
              - - ">="
         | 
| 114 | 
            +
                - !ruby/object:Gem::Version
         | 
| 115 | 
            +
                  version: '0'
         | 
| 116 | 
            +
            requirements: []
         | 
| 117 | 
            +
            rubygems_version: 3.0.8
         | 
| 118 | 
            +
            signing_key:
         | 
| 119 | 
            +
            specification_version: 4
         | 
| 120 | 
            +
            summary: Support for API acrtions
         | 
| 121 | 
            +
            test_files: []
         |