Skip to content

Instantly share code, notes, and snippets.

@rondy
Last active March 2, 2021 11:14
Show Gist options
  • Save rondy/a9f167cca216dfb51d1dc1fac56755b1 to your computer and use it in GitHub Desktop.
Save rondy/a9f167cca216dfb51d1dc1fac56755b1 to your computer and use it in GitHub Desktop.

Revisions

  1. rondy revised this gist Oct 17, 2017. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions 01_functional_objects.md
    Original file line number Diff line number Diff line change
    @@ -6,6 +6,7 @@
    * How should I name my objects that carry behavior? They're nouns or verbs?
    * Should I expose attr_readers/writers/accessors?
    * What kind of input should it receive from constructor/initializers? And what about methods?
    * https://hackernoon.com/api-design-temporal-coupling-2c1687173c7c
    * More consistent style among classes definitions.

    #### Benefits
  2. rondy revised this gist Jun 21, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion 01_functional_objects.md
    Original file line number Diff line number Diff line change
    @@ -12,7 +12,7 @@

    * Message passing is natural;
    * Emphasize **what system does** rather rhan **what system is**;
    * Usage of mocking frameworks can be dropped off;
    * Usage of mocking frameworks can be **dropped off**;

    #### Guidelines

  3. rondy revised this gist Sep 14, 2016. 1 changed file with 0 additions and 163 deletions.
    163 changes: 0 additions & 163 deletions 02_functional_objects_example.rb
    Original file line number Diff line number Diff line change
    @@ -1,163 +0,0 @@
    class ReviseElixirRadarEntry
    def call(entry)
    result = Validation() do
    check { check_url_points_to_an_existing_page(entry[:url]) }
    check { check_domain_matches_url_host(entry[:domain], entry[:url]) }
    check { check_entry_title_matches_page_title(entry[:url], entry[:title]) }
    check { check_utm_campaign_is_valid(entry[:url]) }
    end

    review_result = {
    title: entry[:title]
    }

    case result
    when Success
    review_result[:status] = 'valid'
    when Failure
    review_result[:status] = 'invalid'
    review_result[:errors] = result
    end

    review_result
    end

    private

    def check_url_points_to_an_existing_page(url)
    if CheckUrlPointsToAnExistingPage.new.call(url)
    Success(url)
    else
    Failure('page_not_found')
    end
    end

    def check_domain_matches_url_host(domain, url)
    # case CheckDomainMatchesUrlHost.new.call(domain, url)
    # when true then Success(url)
    # when false then Failure('domain_does_not_match')
    # end
    if CheckDomainMatchesUrlHost.new.call(domain, url)
    Success(url)
    else
    Failure('domain_does_not_match')
    end
    end

    def check_entry_title_matches_page_title(url, entry_title)
    if CheckEntryTitleMatchesPageTitle.new.call(url, entry_title)
    Success(url)
    else
    Failure('page_title_does_not_match')
    end
    end

    def check_utm_campaign_is_valid(url)
    if CheckUtmCampaignIsValid.new.call(url)
    Success(url)
    else
    Failure('wrong_utm_campaign')
    end
    end
    end

    class CheckEntryTitleMatchesPageTitle
    def initialize(get_page_title: nil)
    @get_page_title = get_page_title
    end

    def call(url, entry_title)
    page_title = get_page_title.call(url)

    normalized_page_title =
    normalize_page_title(page_title)

    entry_title_matches_page_title =
    entry_title_matches_page_title?(normalized_page_title, entry_title)

    [entry_title_matches_page_title, normalized_page_title]
    end

    private

    def normalize_page_title(page_title)
    page_title
    .gsub(/\s+/, ' ')
    .strip
    end

    def get_page_title(url)
    @get_page_title ||= begin
    lambda do |url|
    GetPageTitle
    .new(with: :mechanize)
    .call(url)
    end
    end
    end

    def entry_title_matches_page_title?(normalized_page_title, entry_title)
    (normalized_page_title =~ Regexp.new(entry_title.strip))
    end
    end

    class GetPageTitle
    STRATEGIES = {
    mechanize: lambda do |url|
    Mechanize.new.get(url).title
    end
    }

    def initialize(with: strategy)
    @strategy = strategy
    end

    def call(url)
    STRATEGIES.fetch[@strategy].call(url)
    end
    end

    CheckEntryTitleMatchesPageTitle
    .new(
    get_page_title: lambda do |url|
    'Elixir/Erlang Clustering in Kubernetes'
    end
    )
    .call(
    url: 'http://bitwalker.org/posts/2016-08-04-clustering-in-kubernetes',
    entry_title: 'Elixir/Erlang Clustering in Kubernetes'
    )
    # => [true, 'Elixir/Erlang Clustering in Kubernetes']

    class CheckUtmCampaignIsValid
    def initialize(current_issue_number: nil)
    @current_issue_number = current_issue_number
    end

    def call(url)
    [
    is_utm_campaign_valid?(extract_utm_campaign_value_from(url)),
    given_utm_campaign_value
    ]
    end

    private

    def is_utm_campaign_valid?(given_utm_campaign_value)
    (given_utm_campaign_value == current_issue_number.call)
    end

    def extract_utm_campaign_value_from(url)
    parse_query_strings(url)
    .fetch('utm_campaign', [])
    .first
    end

    def parse_query_strings(url)
    CGI.parse(URI.parse(url).query)
    end

    def current_issue_number
    @current_issue_number ||= lambda { $current_issue_number }
    end
    end
  4. rondy revised this gist Sep 14, 2016. 1 changed file with 1 addition and 3 deletions.
    4 changes: 1 addition & 3 deletions 01_functional_objects.md
    Original file line number Diff line number Diff line change
    @@ -33,9 +33,7 @@ end
    ```
    * Public contract is a `#call` method;
    * Enables SRP;
    * Enables composition;
    * Enables polymorphism;
    * Enables to receive Proc/callables objects;
    * Enables composition/polymorphism through proc/callables objects;
    * Receive stateful/impure collaborators through the object initializer;
    * This permits easy mocking/substitution.
    * This resembles curry-like functions;
  5. rondy revised this gist Sep 14, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion 01_functional_objects.md
    Original file line number Diff line number Diff line change
    @@ -6,7 +6,7 @@
    * How should I name my objects that carry behavior? They're nouns or verbs?
    * Should I expose attr_readers/writers/accessors?
    * What kind of input should it receive from constructor/initializers? And what about methods?
    * More consistent style on classes definition.
    * More consistent style among classes definitions.

    #### Benefits

  6. rondy revised this gist Sep 14, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion 01_functional_objects.md
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@

    #### Goals

    * Less questions asked.
    * Less questions asked. E.g:
    * How should I name my objects that carry behavior? They're nouns or verbs?
    * Should I expose attr_readers/writers/accessors?
    * What kind of input should it receive from constructor/initializers? And what about methods?
  7. rondy revised this gist Aug 25, 2016. 1 changed file with 14 additions and 0 deletions.
    14 changes: 14 additions & 0 deletions 01_functional_objects.md
    Original file line number Diff line number Diff line change
    @@ -17,6 +17,20 @@
    #### Guidelines

    * Start class names with a verb;
    * ("do thing" instead of "thing doer");
    ```ruby
    # Bad
    class BackupProcedure
    def perform
    end
    end

    # Good
    class PerformBackupProcedure
    def call
    end
    end
    ```
    * Public contract is a `#call` method;
    * Enables SRP;
    * Enables composition;
  8. rondy revised this gist Aug 25, 2016. 1 changed file with 8 additions and 0 deletions.
    8 changes: 8 additions & 0 deletions 01_functional_objects.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,13 @@
    ## Functional objects on Ruby programming language

    #### Goals

    * Less questions asked.
    * How should I name my objects that carry behavior? They're nouns or verbs?
    * Should I expose attr_readers/writers/accessors?
    * What kind of input should it receive from constructor/initializers? And what about methods?
    * More consistent style on classes definition.

    #### Benefits

    * Message passing is natural;
  9. rondy revised this gist Aug 25, 2016. 3 changed files with 0 additions and 67 deletions.
    File renamed without changes.
    File renamed without changes.
    67 changes: 0 additions & 67 deletions functional_objects_old.md
    Original file line number Diff line number Diff line change
    @@ -1,67 +0,0 @@
    ## Functional objects on Ruby programming language

    #### Benefits

    * Message passing is natural;
    * Emphasize **what system does** rather rhan **what system is**;
    * Usage of mocking frameworks can be dropped off;

    #### Guidelines

    * Start class names with a verb;
    * Public contract is a `#call` method;
    * Enables SRP;
    * Enables composition;
    * Enables polymorphism;
    * Enables to receive Proc/callables objects;
    * Receive stateful/impure collaborators through the object initializer;
    * This permits easy mocking/substitution.
    * This resembles curry-like functions;
    * Receive "pure function" inputs through the `#call` method;
    * Collaborators are also other functional objects (they're named as verbs);
    * The `#call` calling always returns a value, preferably 'result'-like objects;
    * This avoids 'primitive obssesion' anti-pattern;
    * Consider monadics operations;
    * Define stateful/impure functions as default implementation, in case nothing is received;
    ```ruby
    #...
    private

    def get_page_title
    @get_page_title ||= begin
    lambda do |url|
    mechanize = Mechanize.new
    mechanize.get(url).title
    end
    end
    end
    end
    ```
    * Object internal state is used only for stateful/impure collaborators.
    * Stateful/impure functions are always returned as closures/lambda;
    ```ruby
    extract_utm_campaign_value_from(url) # is pure
    get_page_title.call(url) # is impure
    ```

    #### Quote from "Functional and Reactive Domain Modeling" book

    ```
    # Why mixing domain logic and side effects is bad
    ### Entanglement of domain logic and side effects.
    Violates separation of concerns. Domain logic and side effects are orthogonal
    to each other—entanglement violates a basic software engineering principle.
    ### Difficult to unit test.
    If domain logic is entangled with side effects, unit testing becomes
    difficult. You need to resort to mocking stuff that leads to other
    complications in your source code.
    ### Difficult to reason about the domain logic.
    You can’t reason about the domain logic that’s entangled with the side effect.
    ### Side effects don’t compose and hinder modularity of your code.
    Your entangled code remains an island that can’t be composed with other
    functions.
    ```
  10. rondy revised this gist Aug 25, 2016. 1 changed file with 67 additions and 0 deletions.
    67 changes: 67 additions & 0 deletions functional_objects_old.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,67 @@
    ## Functional objects on Ruby programming language

    #### Benefits

    * Message passing is natural;
    * Emphasize **what system does** rather rhan **what system is**;
    * Usage of mocking frameworks can be dropped off;

    #### Guidelines

    * Start class names with a verb;
    * Public contract is a `#call` method;
    * Enables SRP;
    * Enables composition;
    * Enables polymorphism;
    * Enables to receive Proc/callables objects;
    * Receive stateful/impure collaborators through the object initializer;
    * This permits easy mocking/substitution.
    * This resembles curry-like functions;
    * Receive "pure function" inputs through the `#call` method;
    * Collaborators are also other functional objects (they're named as verbs);
    * The `#call` calling always returns a value, preferably 'result'-like objects;
    * This avoids 'primitive obssesion' anti-pattern;
    * Consider monadics operations;
    * Define stateful/impure functions as default implementation, in case nothing is received;
    ```ruby
    #...
    private

    def get_page_title
    @get_page_title ||= begin
    lambda do |url|
    mechanize = Mechanize.new
    mechanize.get(url).title
    end
    end
    end
    end
    ```
    * Object internal state is used only for stateful/impure collaborators.
    * Stateful/impure functions are always returned as closures/lambda;
    ```ruby
    extract_utm_campaign_value_from(url) # is pure
    get_page_title.call(url) # is impure
    ```

    #### Quote from "Functional and Reactive Domain Modeling" book

    ```
    # Why mixing domain logic and side effects is bad
    ### Entanglement of domain logic and side effects.
    Violates separation of concerns. Domain logic and side effects are orthogonal
    to each other—entanglement violates a basic software engineering principle.
    ### Difficult to unit test.
    If domain logic is entangled with side effects, unit testing becomes
    difficult. You need to resort to mocking stuff that leads to other
    complications in your source code.
    ### Difficult to reason about the domain logic.
    You can’t reason about the domain logic that’s entangled with the side effect.
    ### Side effects don’t compose and hinder modularity of your code.
    Your entangled code remains an island that can’t be composed with other
    functions.
    ```
  11. rondy revised this gist Aug 24, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion functional_objects.md
    Original file line number Diff line number Diff line change
    @@ -18,6 +18,7 @@
    * This permits easy mocking/substitution.
    * This resembles curry-like functions;
    * Receive "pure function" inputs through the `#call` method;
    * Collaborators are also other functional objects (they're named as verbs);
    * The `#call` calling always returns a value, preferably 'result'-like objects;
    * This avoids 'primitive obssesion' anti-pattern;
    * Consider monadics operations;
    @@ -37,7 +38,6 @@
    end
    ```
    * Object internal state is used only for stateful/impure collaborators.
    * Collaborators are also other functional objects (they're named as verbs);
    * Stateful/impure functions are always returned as closures/lambda;
    ```ruby
    extract_utm_campaign_value_from(url) # is pure
  12. rondy revised this gist Aug 24, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion functional_objects.md
    Original file line number Diff line number Diff line change
    @@ -44,7 +44,7 @@ end
    get_page_title.call(url) # is impure
    ```

    #### Quote from book "Functional and Reactive Domain Modeling" book
    #### Quote from "Functional and Reactive Domain Modeling" book

    ```
    # Why mixing domain logic and side effects is bad
  13. rondy revised this gist Aug 24, 2016. 1 changed file with 23 additions and 1 deletion.
    24 changes: 23 additions & 1 deletion functional_objects.md
    Original file line number Diff line number Diff line change
    @@ -6,7 +6,7 @@
    * Emphasize **what system does** rather rhan **what system is**;
    * Usage of mocking frameworks can be dropped off;

    ### Guidelines
    #### Guidelines

    * Start class names with a verb;
    * Public contract is a `#call` method;
    @@ -43,3 +43,25 @@ end
    extract_utm_campaign_value_from(url) # is pure
    get_page_title.call(url) # is impure
    ```

    #### Quote from book "Functional and Reactive Domain Modeling" book

    ```
    # Why mixing domain logic and side effects is bad
    ### Entanglement of domain logic and side effects.
    Violates separation of concerns. Domain logic and side effects are orthogonal
    to each other—entanglement violates a basic software engineering principle.
    ### Difficult to unit test.
    If domain logic is entangled with side effects, unit testing becomes
    difficult. You need to resort to mocking stuff that leads to other
    complications in your source code.
    ### Difficult to reason about the domain logic.
    You can’t reason about the domain logic that’s entangled with the side effect.
    ### Side effects don’t compose and hinder modularity of your code.
    Your entangled code remains an island that can’t be composed with other
    functions.
    ```
  14. rondy revised this gist Aug 24, 2016. 1 changed file with 9 additions and 4 deletions.
    13 changes: 9 additions & 4 deletions functional_objects.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,12 @@
    #### Functional objects on Ruby programming language
    ## Functional objects on Ruby programming language

    #### Benefits

    * Message passing is natural;
    * Emphasize **what system does** rather rhan **what system is**;
    * Usage of mocking frameworks can be dropped off;

    ### Guidelines

    * Start class names with a verb;
    * Public contract is a `#call` method;
    @@ -35,6 +43,3 @@ end
    extract_utm_campaign_value_from(url) # is pure
    get_page_title.call(url) # is impure
    ```
    * Message passing is natural;
    * Emphasize **what system does** rather rhan **what system is**;
    * Usage of mocking frameworks can be dropped off;
  15. rondy revised this gist Aug 24, 2016. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion functional_objects.md
    Original file line number Diff line number Diff line change
    @@ -35,5 +35,6 @@ end
    extract_utm_campaign_value_from(url) # is pure
    get_page_title.call(url) # is impure
    ```
    * Usage of mocking frameworks can be dropped off;
    * Message passing is natural;
    * Emphasize **what system does** rather rhan **what system is**;
    * Usage of mocking frameworks can be dropped off;
  16. rondy revised this gist Aug 24, 2016. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions functional_objects.md
    Original file line number Diff line number Diff line change
    @@ -35,4 +35,5 @@ end
    extract_utm_campaign_value_from(url) # is pure
    get_page_title.call(url) # is impure
    ```
    * Usage of mocking frameworks can be dropped off;
    * Message passing is natural;
  17. rondy revised this gist Aug 24, 2016. 1 changed file with 19 additions and 4 deletions.
    23 changes: 19 additions & 4 deletions functional_objects.md
    Original file line number Diff line number Diff line change
    @@ -6,16 +6,31 @@
    * Enables composition;
    * Enables polymorphism;
    * Enables to receive Proc/callables objects;
    * Receive stateful/impure functions through the object initializer;
    * Receive stateful/impure collaborators through the object initializer;
    * This permits easy mocking/substitution.
    * Receive pure function inputs through the `#call` method;
    * This resembles curry-like functions;
    * This resembles curry-like functions;
    * Receive "pure function" inputs through the `#call` method;
    * The `#call` calling always returns a value, preferably 'result'-like objects;
    * This avoids 'primitive obssesion' anti-pattern;
    * Consider monadics operations;
    * Define stateful/impure functions as default implementation, in case nothing is received;
    ```ruby
    #...
    private

    def get_page_title
    @get_page_title ||= begin
    lambda do |url|
    mechanize = Mechanize.new
    mechanize.get(url).title
    end
    end
    end
    end
    ```
    * Object internal state is used only for stateful/impure collaborators.
    * * Stateful/impure functions are always returned as closures/lambda;
    * Collaborators are also other functional objects (they're named as verbs);
    * Stateful/impure functions are always returned as closures/lambda;
    ```ruby
    extract_utm_campaign_value_from(url) # is pure
    get_page_title.call(url) # is impure
  18. rondy revised this gist Aug 24, 2016. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions functional_objects.md
    Original file line number Diff line number Diff line change
    @@ -14,8 +14,8 @@
    * This avoids 'primitive obssesion' anti-pattern;
    * Consider monadics operations;
    * Define stateful/impure functions as default implementation, in case nothing is received;
    * Stateful/impure functions are always returned as closures/lambda;
    * Object state is uded only for atateful/impure collaborators.
    * Object internal state is used only for stateful/impure collaborators.
    * * Stateful/impure functions are always returned as closures/lambda;
    ```ruby
    extract_utm_campaign_value_from(url) # is pure
    get_page_title.call(url) # is impure
  19. rondy revised this gist Aug 24, 2016. 1 changed file with 101 additions and 0 deletions.
    101 changes: 101 additions & 0 deletions example.rb
    Original file line number Diff line number Diff line change
    @@ -60,3 +60,104 @@ def check_utm_campaign_is_valid(url)
    end
    end
    end

    class CheckEntryTitleMatchesPageTitle
    def initialize(get_page_title: nil)
    @get_page_title = get_page_title
    end

    def call(url, entry_title)
    page_title = get_page_title.call(url)

    normalized_page_title =
    normalize_page_title(page_title)

    entry_title_matches_page_title =
    entry_title_matches_page_title?(normalized_page_title, entry_title)

    [entry_title_matches_page_title, normalized_page_title]
    end

    private

    def normalize_page_title(page_title)
    page_title
    .gsub(/\s+/, ' ')
    .strip
    end

    def get_page_title(url)
    @get_page_title ||= begin
    lambda do |url|
    GetPageTitle
    .new(with: :mechanize)
    .call(url)
    end
    end
    end

    def entry_title_matches_page_title?(normalized_page_title, entry_title)
    (normalized_page_title =~ Regexp.new(entry_title.strip))
    end
    end

    class GetPageTitle
    STRATEGIES = {
    mechanize: lambda do |url|
    Mechanize.new.get(url).title
    end
    }

    def initialize(with: strategy)
    @strategy = strategy
    end

    def call(url)
    STRATEGIES.fetch[@strategy].call(url)
    end
    end

    CheckEntryTitleMatchesPageTitle
    .new(
    get_page_title: lambda do |url|
    'Elixir/Erlang Clustering in Kubernetes'
    end
    )
    .call(
    url: 'http://bitwalker.org/posts/2016-08-04-clustering-in-kubernetes',
    entry_title: 'Elixir/Erlang Clustering in Kubernetes'
    )
    # => [true, 'Elixir/Erlang Clustering in Kubernetes']

    class CheckUtmCampaignIsValid
    def initialize(current_issue_number: nil)
    @current_issue_number = current_issue_number
    end

    def call(url)
    [
    is_utm_campaign_valid?(extract_utm_campaign_value_from(url)),
    given_utm_campaign_value
    ]
    end

    private

    def is_utm_campaign_valid?(given_utm_campaign_value)
    (given_utm_campaign_value == current_issue_number.call)
    end

    def extract_utm_campaign_value_from(url)
    parse_query_strings(url)
    .fetch('utm_campaign', [])
    .first
    end

    def parse_query_strings(url)
    CGI.parse(URI.parse(url).query)
    end

    def current_issue_number
    @current_issue_number ||= lambda { $current_issue_number }
    end
    end
  20. rondy revised this gist Aug 24, 2016. 1 changed file with 62 additions and 0 deletions.
    62 changes: 62 additions & 0 deletions example.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,62 @@
    class ReviseElixirRadarEntry
    def call(entry)
    result = Validation() do
    check { check_url_points_to_an_existing_page(entry[:url]) }
    check { check_domain_matches_url_host(entry[:domain], entry[:url]) }
    check { check_entry_title_matches_page_title(entry[:url], entry[:title]) }
    check { check_utm_campaign_is_valid(entry[:url]) }
    end

    review_result = {
    title: entry[:title]
    }

    case result
    when Success
    review_result[:status] = 'valid'
    when Failure
    review_result[:status] = 'invalid'
    review_result[:errors] = result
    end

    review_result
    end

    private

    def check_url_points_to_an_existing_page(url)
    if CheckUrlPointsToAnExistingPage.new.call(url)
    Success(url)
    else
    Failure('page_not_found')
    end
    end

    def check_domain_matches_url_host(domain, url)
    # case CheckDomainMatchesUrlHost.new.call(domain, url)
    # when true then Success(url)
    # when false then Failure('domain_does_not_match')
    # end
    if CheckDomainMatchesUrlHost.new.call(domain, url)
    Success(url)
    else
    Failure('domain_does_not_match')
    end
    end

    def check_entry_title_matches_page_title(url, entry_title)
    if CheckEntryTitleMatchesPageTitle.new.call(url, entry_title)
    Success(url)
    else
    Failure('page_title_does_not_match')
    end
    end

    def check_utm_campaign_is_valid(url)
    if CheckUtmCampaignIsValid.new.call(url)
    Success(url)
    else
    Failure('wrong_utm_campaign')
    end
    end
    end
  21. rondy revised this gist Aug 24, 2016. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions functional_objects.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    #### Functional objects
    #### Functional objects on Ruby programming language

    * Start with a verb;
    * Start class names with a verb;
    * Public contract is a `#call` method;
    * Enables SRP;
    * Enables composition;
    @@ -15,9 +15,9 @@
    * Consider monadics operations;
    * Define stateful/impure functions as default implementation, in case nothing is received;
    * Stateful/impure functions are always returned as closures/lambda;
    * Object state is uded only for atateful/impure collaborators.
    ```ruby
    extract_utm_campaign_value_from(url) # is pure
    get_page_title.call(url) # is impure
    ```
    * Consider to be event-driven;
    * Message passing is natural;
  22. rondy revised this gist Aug 24, 2016. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions functional_objects.md
    Original file line number Diff line number Diff line change
    @@ -12,10 +12,12 @@
    * This resembles curry-like functions;
    * The `#call` calling always returns a value, preferably 'result'-like objects;
    * This avoids 'primitive obssesion' anti-pattern;
    * Consider monadics operations;
    * Define stateful/impure functions as default implementation, in case nothing is received;
    * Stateful/impure functions are always returned as closures/lambda;
    ```ruby
    extract_utm_campaign_value_from(url) # is pure
    get_page_title.call(url) # is impure
    ```
    * Consider to be event-driven;
    * Message passing is natural;
  23. rondy revised this gist Aug 24, 2016. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions functional_objects.md
    Original file line number Diff line number Diff line change
    @@ -8,13 +8,13 @@
    * Enables to receive Proc/callables objects;
    * Receive stateful/impure functions through the object initializer;
    * This permits easy mocking/substitution.
    * Receive pure function inputs through the `#call` method.
    * This resembles curry-like functions.
    * The `#call` calling always returns a value, preferably 'result'-like objects
    * Receive pure function inputs through the `#call` method;
    * This resembles curry-like functions;
    * The `#call` calling always returns a value, preferably 'result'-like objects;
    * This avoids 'primitive obssesion' anti-pattern;
    * Define stateful/impure functions as default implementation, in case nothing is received;
    * Stateful/impure functions are always returned as closures/lambda;
    ```
    ```ruby
    extract_utm_campaign_value_from(url) # is pure
    get_page_title.call(url) # is impure
    ```
  24. rondy revised this gist Aug 24, 2016. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions functional_objects.md
    Original file line number Diff line number Diff line change
    @@ -2,6 +2,10 @@

    * Start with a verb;
    * Public contract is a `#call` method;
    * Enables SRP;
    * Enables composition;
    * Enables polymorphism;
    * Enables to receive Proc/callables objects;
    * Receive stateful/impure functions through the object initializer;
    * This permits easy mocking/substitution.
    * Receive pure function inputs through the `#call` method.
  25. rondy created this gist Aug 24, 2016.
    17 changes: 17 additions & 0 deletions functional_objects.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,17 @@
    #### Functional objects

    * Start with a verb;
    * Public contract is a `#call` method;
    * Receive stateful/impure functions through the object initializer;
    * This permits easy mocking/substitution.
    * Receive pure function inputs through the `#call` method.
    * This resembles curry-like functions.
    * The `#call` calling always returns a value, preferably 'result'-like objects
    * This avoids 'primitive obssesion' anti-pattern;
    * Define stateful/impure functions as default implementation, in case nothing is received;
    * Stateful/impure functions are always returned as closures/lambda;
    ```
    extract_utm_campaign_value_from(url) # is pure
    get_page_title.call(url) # is impure
    ```
    * Message passing is natural;