### Configuring Operations with SmartProperties in Ruby Source: https://github.com/t6d/composable_operations/blob/master/README.md Illustrates how to use SmartProperties to define configurable properties for an operation. Shows setting default values, type conversions, validation, and required properties. Includes an example of initializing an operation with custom property values. ```ruby class Indention < ComposableOperations::Operation processes :text property :indent, default: 2, converts: lambda { |value| value.to_s.to_i }, accepts: lambda { |value| value >= 0 }, required: true def execute text.split("\n").map { |line| " " * indent + line }.join("\n") end end Indention.perform("Hello World", indent: 4) # => " Hello World" ``` -------------------------------- ### Create a Configurable Operation with Properties in Ruby Source: https://context7.com/t6d/composable_operations/llms.txt Shows how to add configurable properties to an operation using SmartProperties. Properties can have default values, type conversions, validation rules, and be marked as required. The example demonstrates using a default indent and overriding it via an options hash. ```ruby class Indention < ComposableOperations::Operation processes :text property :indent, default: 2, converts: ->(value) { value.to_s.to_i }, accepts: ->(value) { value >= 0 }, required: true def execute text.split("\n").map { |line| " " * indent + line }.join("\n") end end # Use default indent Indention.perform("Hello World") # => " Hello World" # Override indent via options hash Indention.perform("Hello World", indent: 4) # => " Hello World" # Multi-line text Indention.perform("Line 1\nLine 2", indent: 3) # => " Line 1\n Line 2" ``` -------------------------------- ### Create an Operation with Multiple Input Arguments in Ruby Source: https://context7.com/t6d/composable_operations/llms.txt Illustrates how to define an operation that accepts multiple input arguments using the `processes` macro. Each argument is automatically converted into a getter method within the operation class. The example shows passing multiple arguments during execution. ```ruby class StringMultiplier < ComposableOperations::Operation processes :string, :multiplier def execute string * multiplier end end # Pass multiple arguments StringMultiplier.perform("-", 3) # => "---" StringMultiplier.perform("hello ", 2) # => "hello hello " ``` -------------------------------- ### Create a Composed Operation (Pipeline) in Ruby Source: https://context7.com/t6d/composable_operations/llms.txt Demonstrates how to chain multiple operations together into a pipeline using `ComposableOperations::ComposedOperation`. The output of each operation serves as the input for the next. This example composes a `DateExtractor` and a `DateArrayToTimeConverter`. ```ruby class DateArrayToTimeConverter < ComposableOperations::Operation processes :collection_of_date_arrays def execute collection_of_date_arrays.map do |date_array| Time.new(*(date_array.map(&:to_i))) end end end # Compose operations into a pipeline class DateParser < ComposableOperations::ComposedOperation use DateExtractor use DateArrayToTimeConverter end # Execute the pipeline DateParser.perform("Created on 2013-06-10 and 2024-01-15.") # => [2013-06-10 00:00:00 +0000, 2024-01-15 00:00:00 +0000] # Instance method execution parser = DateParser.new("Updated on 2024-03-20.") parser.perform # => [2024-03-20 00:00:00 +0000] parser.succeeded? # => true ``` -------------------------------- ### Compose Operations with Dynamic Configuration in Ruby Source: https://context7.com/t6d/composable_operations/llms.txt Explains how to pass configuration options to operations within a composed operation, including dynamic values using lambda expressions. This example composes a string generator, capitalizer, and repeater, with the repeater's multiplicator dynamically set by a property on the composed operation. ```ruby class StringGenerator < ComposableOperations::Operation def execute "chunky bacon" end end class StringCapitalizer < ComposableOperations::Operation processes :text def execute text.upcase end end class StringRepeater < ComposableOperations::Operation processes :text property :multiplicator, default: 1, converts: :to_i, required: true property :separator, default: ' ', converts: :to_s, required: true def execute (Array(text) * multiplicator).join(separator) end end # Compose with static and dynamic configuration class FormattedStringGenerator < ComposableOperations::ComposedOperation property :repeat_count, default: 3 use StringGenerator use StringCapitalizer use StringRepeater, separator: ' - ', multiplicator: -> { repeat_count } end FormattedStringGenerator.perform # => "CHUNKY BACON - CHUNKY BACON - CHUNKY BACON" FormattedStringGenerator.perform(repeat_count: 2) # => "CHUNKY BACON - CHUNKY BACON" ``` -------------------------------- ### Execute a Composed Operation (DateParser) in Ruby Source: https://github.com/t6d/composable_operations/blob/master/README.md Demonstrates how to execute the 'DateParser' composed operation in Ruby. Similar to individual operations, it can be executed by creating an instance and calling `#perform`, or by directly calling `.perform` on the class. This example shows the conversion of a date string into a Time object. ```ruby text = "This gem was first published on 2013-06-10." parser = DateParser.new(text) parser.perform # => 2013-06-07 00:00:00 +0200 DateParser.perform(text) # => 2013-06-07 00:00:00 +0200 ``` -------------------------------- ### Before and After Callbacks for Operations (Ruby) Source: https://context7.com/t6d/composable_operations/llms.txt Shows how to use `before` and `after` callbacks to add logic for preparation and finalization. These callbacks help keep the `execute` method clean by handling pre-execution validation and post-execution processing. ```ruby class DataProcessor < ComposableOperations::Operation processes :data before do # Validate input before execution fail "data cannot be nil" if data.nil? fail "data must be an array" unless data.is_a?(Array) end after do # Post-process or validate result fail "processing produced empty result" if result.empty? end def execute data.map { |item| item.to_s.strip.downcase } end end # Successful execution DataProcessor.perform([" Hello ", "WORLD "]) # => ["hello", "world"] # Fails in before callback processor = DataProcessor.new(nil) processor.perform processor.failed? # => true processor.message # => "data cannot be nil" # Fails in after callback processor = DataProcessor.new([]) processor.perform processor.failed? # => true processor.message # => "processing produced empty result" ``` -------------------------------- ### Create a Basic Operation in Ruby Source: https://context7.com/t6d/composable_operations/llms.txt Demonstrates how to define a basic operation by subclassing `ComposableOperations::Operation` and implementing the `#execute` method. It uses the `processes` macro for input arguments and shows both class and instance method execution. Raises an exception on failure for class method and returns nil for instance method. ```ruby require 'composable_operations' class DateExtractor < ComposableOperations::Operation processes :text def execute text.scan(/(\d{4})-(\d{2})-(\d{2})/) end end # Execute via class method (raises exception on failure) result = DateExtractor.perform("Published on 2013-06-10 and updated on 2024-01-15.") # => [["2013", "06", "10"], ["2024", "01", "15"]] # Execute via instance method (returns nil on failure, sets state) extractor = DateExtractor.new("Published on 2013-06-10.") extractor.perform # => [["2013", "06", "10"]] extractor.succeeded? # => true extractor.result # => [["2013", "06", "10"]] ``` -------------------------------- ### Halting vs. Aborting Operations in Ruby Source: https://github.com/t6d/composable_operations/blob/master/README.md Demonstrates the difference between halting an operation (updating state) and aborting an operation (raising an exception) in Ruby. Shows how to check operation status and handle errors. ```ruby class StrictDateParser < DateParser def execute result = super fail "no timestamp found" if result.empty? result end end class LessStrictDateParser < DateParser def execute result = super halt "no timestamp found" if result.empty? result end end parser = StrictDateParser.new("") parser.message # => "no timestamp found" parser.perform # => nil parser.succeeded? # => false parser.halted? # => false parser.failed? # => true StrictDateParser.perform("") # => ComposableOperations::OperationError: no timestamp found parser = LessStricDateParser.new("") parser.message # => "no timestamp found" parser.perform # => nil parser.succeeded? # => false parser.halted? # => true parser.failed? # => false StrictDateParser.perform("") # => nil ``` -------------------------------- ### Configuring Composed Operations in Ruby Source: https://github.com/t6d/composable_operations/blob/master/README.md Demonstrates how to configure individual operations that are part of a composed operation. Shows the usage of the `.use` method with a hash of options to set properties for a nested operation. ```ruby class SomeComposedOperation < ComposableOperations::ComposedOperation # ... use Indention, indent: 4 # ... end ``` -------------------------------- ### Using Callbacks for Operation Logic in Ruby Source: https://github.com/t6d/composable_operations/blob/master/README.md Shows an alternative implementation of an operation using `after` callbacks to handle logic like validation, avoiding clutter in the main `execute` method. Demonstrates how callbacks affect operation state and error handling. ```ruby class StrictDateParser < DateParser after do fail "no timestamp found" if result.empty? end end parser = StrictDateParser.new("") parser.message # => "no timestamp found" parser.perform # => nil parser.failed? # => true StrictDateParser.perform("") # => ComposableOperations::OperationError: no timestamp found ``` -------------------------------- ### Compose Operations using Factory Method (Ruby) Source: https://context7.com/t6d/composable_operations/llms.txt Demonstrates how to use the `.compose` class method to create composed operations without defining a new class. This method can accept operation classes directly or a block for more granular control. ```ruby class Upcase < ComposableOperations::Operation processes :text def execute text.upcase end end class Reverse < ComposableOperations::Operation processes :text def execute text.reverse end end # Quick composition using factory method TextTransformer = ComposableOperations::ComposedOperation.compose(Upcase, Reverse) TextTransformer.perform("hello") # => "OLLEH" # Or with a block for more control CustomTransformer = ComposableOperations::ComposedOperation.compose do use Upcase use Reverse end CustomTransformer.perform("world") # => "DLROW" ``` -------------------------------- ### Control Flow: Fail and Halt Operations (Ruby) Source: https://context7.com/t6d/composable_operations/llms.txt Illustrates the use of `fail` to abort an operation with an error and `halt` to stop execution gracefully, optionally returning a value. This is useful for handling expected stopping conditions. ```ruby class StrictDateParser < ComposableOperations::ComposedOperation use DateExtractor use DateArrayToTimeConverter # Fail if no dates found (raises exception with class method) after do fail "no timestamp found" if result.empty? end end class LenientDateParser < ComposableOperations::ComposedOperation use DateExtractor use DateArrayToTimeConverter # Halt gracefully if no dates (returns nil, no exception) after do halt "no timestamp found" if result.empty? end end # StrictDateParser fails with exception begin StrictDateParser.perform("no dates here") rescue ComposableOperations::OperationError => e puts e.message # => "no timestamp found" end # Using instance method to check failure state strict = StrictDateParser.new("no dates here") strict.perform # => nil strict.failed? # => true strict.message # => "no timestamp found" # LenientDateParser halts gracefully LenientDateParser.perform("no dates here") # => nil (no exception raised) lenient = LenientDateParser.new("no dates here") lenient.perform # => nil lenient.halted? # => true lenient.failed? # => false lenient.message # => "no timestamp found" ``` -------------------------------- ### Custom Exception Types for Operations (Ruby) Source: https://context7.com/t6d/composable_operations/llms.txt Explains how to specify custom exception classes for failed operations using the `raises` macro. This allows for more specific error handling and clearer communication of failure reasons. ```ruby class ValidationError < StandardError; end class EmailValidator < ComposableOperations::Operation processes :email raises ValidationError def execute fail "invalid email format" unless email =~ /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i email.downcase end end # Raises custom exception type begin EmailValidator.perform("invalid-email") rescue ValidationError => e puts "Caught ValidationError: #{e.message}" # => "Caught ValidationError: invalid email format" end # Instance access to exception validator = EmailValidator.new("bad@") validator.perform validator.exception.class # => ValidationError validator.exception.message # => "invalid email format" ``` -------------------------------- ### Implement and Use a Division Operation Source: https://context7.com/t6d/composable_operations/llms.txt This Ruby code defines a `DivisionOperation` that inherits from `ComposableOperations::Operation`. It includes input processing, execution logic with error handling for division by zero, and demonstrates how to access the operation's state and results for both successful and failed executions. ```ruby class DivisionOperation < ComposableOperations::Operation processes :dividend, :divisor def execute fail "division by zero" if divisor == 0 dividend.to_f / divisor end end # Successful operation op = DivisionOperation.new(10, 2) op.perform # => 5.0 op.succeeded? # => true op.failed? # => false op.halted? # => false op.result # => 5.0 op.message # => nil op.input # => [10, 2] # Failed operation op = DivisionOperation.new(10, 0) op.perform # => nil op.succeeded? # => false op.failed? # => true op.halted? # => false op.result # => nil op.message # => "division by zero" op.exception # => # op.backtrace # => [...stack trace...] ``` -------------------------------- ### Execute a Date Extraction Operation in Ruby Source: https://github.com/t6d/composable_operations/blob/master/README.md Demonstrates two ways to execute the 'DateExtractor' operation in Ruby. The first method involves creating an instance of the operation and calling `#perform`. The second method directly calls `.perform` on the class. The former returns nil on failure, while the latter raises an exception. ```ruby text = "This gem was first published on 2013-06-10." extractor = DateExtractor.new(text) extractor.perform # => [["2013", "06", "10"]] DateExtractor.perform(text) # => [["2013", "06", "10"]] ``` -------------------------------- ### RSpec Testing Matchers for Composable Operations (Ruby) Source: https://context7.com/t6d/composable_operations/llms.txt Demonstrates the use of built-in RSpec matchers provided by the Composable Operations gem for testing operation success, failure, and halting behavior. These matchers simplify test writing for composed and individual operations. ```ruby require 'composable_operations/matcher' RSpec.describe DateExtractor do it { is_expected.to succeed_to_perform.when_initialized_with("2024-01-15").and_return([["2024", "01", "15"]]) } it { is_expected.to succeed_to_perform.when_initialized_with("no dates").and_return([]) } end RSpec.describe StrictDateParser do it { is_expected.to fail_to_perform.when_initialized_with("no dates").because("no timestamp found") } it { is_expected.to succeed_to_perform.when_initialized_with("2024-01-15") } end RSpec.describe LenientDateParser do it { is_expected.to halt_while_performing.when_initialized_with("no dates").because("no timestamp found") } end RSpec.describe StringMultiplier do it { is_expected.to succeed_to_perform.when_initialized_with("-", 3).and_return("---") } it { is_expected.to succeed_to_perform.when_initialized_with("ab", 2).and_return("abab") } end ``` -------------------------------- ### Test Composed Operation Structure with RSpec Source: https://context7.com/t6d/composable_operations/llms.txt This snippet demonstrates how to test the structure of composed operations using RSpec matchers. It verifies that a specific operation class utilizes the expected sequence of other operations. ```ruby RSpec.describe DateParser do it { is_expected.to utilize_operations(DateExtractor, DateArrayToTimeConverter) } end ``` -------------------------------- ### Define a Composed Operation (DateParser) in Ruby Source: https://github.com/t6d/composable_operations/blob/master/README.md This Ruby code defines a Composed Operation named 'DateParser' by assembling two previously defined operations: 'DateExtractor' and 'DateArrayToTimeObjectConverter'. It uses the `.use` macro to specify the order and composition of these operations. ```ruby class DateParser < ComposableOperations::ComposedOperation use DateExtractor use DateArrayToTimeObjectConverter end ``` -------------------------------- ### Define a Date Extraction Operation in Ruby Source: https://github.com/t6d/composable_operations/blob/master/README.md This Ruby code defines a Composable Operation named 'DateExtractor' that extracts dates in 'yyyy-mm-dd' format from a given text. It uses the `.processes` macro to define an input parameter 'text' and implements the `#execute` method to perform the extraction using a regular expression. ```ruby class DateExtractor < ComposableOperations::Operation processes :text def execute text.scan(/(\d{4})-(\d{2})-(\d{2})/) end end ``` -------------------------------- ### Define a Date Array to Time Object Converter Operation in Ruby Source: https://github.com/t6d/composable_operations/blob/master/README.md This Ruby code defines a Composable Operation named 'DateArrayToTimeObjectConverter' that converts arrays of date strings (e.g., from the DateExtractor) into Time objects. It uses the `.processes` macro for input and maps over the input collection to create Time objects. ```ruby class DateArrayToTimeObjectConverter < ComposableOperations::Operation processes :collection_of_date_arrays def execute collection_of_date_arrays.map do |date_array| Time.new(*(date_array.map(&:to_i))) end end end ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.