What is an organizer service?

  • An organizer service composes other services (or methods) via steps. If any step is not successful, the pipeline stops and that step's result is returned as the whole service's result.

    class AssertFileExists
      include ConvenientService::Standard::Config
    
      attr_reader :path
    
      def initialize(path:)
        @path = path
      end
    
      def result
        return failure("File does not exist at path `#{path}`") unless File.exist?(path)
    
        success
      end
    end
    
    class AssertFileNotEmpty
      include ConvenientService::Standard::Config
    
      attr_reader :path
    
      def initialize(path:)
        @path = path
      end
    
      def result
        return failure("File is empty at path `#{path}`") if File.empty?(path)
    
        success
      end
    end
    
    class ReadFileContent
      include ConvenientService::Standard::Config
    
      step AssertFileExists, in: :path
      step AssertFileNotEmpty, in: :path
      step :result, in: :path, out: :content
    
      attr_reader :path
    
      def initialize(path:)
        @path = path
      end
    
      def result
        success(content: File.read(path))
      end
    end
  • If AssertFileExists fails, the pipeline stops there - AssertFileNotEmpty and step :result never run.

    result = ReadFileContent.result(path: "/tmp/non_existent.txt")
    
    result.success?
    # => false
    
    result.original_service.class
    # => AssertFileExists
  • The same applies to AssertFileNotEmpty - when it fails, step :result is skipped.

    File.write("/tmp/empty.txt", "")
    
    result = ReadFileContent.result(path: "/tmp/empty.txt")
    
    result.success?
    # => false
    
    result.original_service.class
    # => AssertFileNotEmpty
  • When every step succeeds, ReadFileContent returns the final step :result result.

    File.write("/tmp/hello.txt", "Hello!")
    
    result = ReadFileContent.result(path: "/tmp/hello.txt")
    
    result.success?
    # => true
    
    result.data[:content]
    # => "Hello!"
  • An organizer service is contrasted with a regular service, which implements result directly instead of composing steps.

See also

Sources