forester 0.0.4 → 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 +4 -4
- data/forester.gemspec +4 -4
- data/lib/forester/aggregators.rb +44 -23
- data/lib/forester/tree_node.rb +31 -0
- data/lib/forester/version.rb +2 -3
- data/test/test_treenode.rb +40 -0
- metadata +20 -20
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: ca08cece8313d3e3c8b20bae94f78163b81853cb
         | 
| 4 | 
            +
              data.tar.gz: d6b07a8b064d28e35b302a9999f5c45b8a0bcdb2
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 696d7af03b121cba11c01a3fb75aea488edf4a56a415a266bf3c2971f8111358dac17e40a06a110aba00171fd838306034337bbe1b17f9b337c6c91f6676fcd8
         | 
| 7 | 
            +
              data.tar.gz: 3ca6bd73015e51026f8aec700ce061affccea8540db8eedab15b6967ae0421931e5497145a59762c53734ac10502f617f38fb24bab4b9aba756a05f14f7070c1
         | 
    
        data/forester.gemspec
    CHANGED
    
    | @@ -6,7 +6,7 @@ require 'forester/version' | |
| 6 6 | 
             
            Gem::Specification.new do |s|
         | 
| 7 7 | 
             
              s.name        = 'forester'
         | 
| 8 8 | 
             
              s.version     = Forester::Version
         | 
| 9 | 
            -
              s.date        = '2016-07- | 
| 9 | 
            +
              s.date        = '2016-07-24'
         | 
| 10 10 | 
             
              s.summary     = "A gem to represent and interact with tree data structures"
         | 
| 11 11 | 
             
              s.description = "Based on rubytree and enzymator, this gem lets you build trees and run queries against them."
         | 
| 12 12 | 
             
              s.authors     = ["Eugenio Bruno"]
         | 
| @@ -19,10 +19,10 @@ Gem::Specification.new do |s| | |
| 19 19 | 
             
              s.test_files    = s.files.grep(%r{^(test|spec|features)/})
         | 
| 20 20 | 
             
              s.require_paths = ['lib']
         | 
| 21 21 |  | 
| 22 | 
            -
              s.required_ruby_version = '>=  | 
| 22 | 
            +
              s.required_ruby_version = '>= 2.0.0'
         | 
| 23 23 |  | 
| 24 | 
            -
              s.add_runtime_dependency 'rubytree', [' | 
| 25 | 
            -
              s.add_runtime_dependency 'enzymator', [' | 
| 24 | 
            +
              s.add_runtime_dependency 'rubytree', ['0.9.7']
         | 
| 25 | 
            +
              s.add_runtime_dependency 'enzymator', ['1.0.0']
         | 
| 26 26 |  | 
| 27 27 | 
             
              s.add_development_dependency 'rake', ['~> 11.2']
         | 
| 28 28 | 
             
              s.add_development_dependency 'minitest', ['~> 5.9']
         | 
    
        data/lib/forester/aggregators.rb
    CHANGED
    
    | @@ -1,43 +1,64 @@ | |
| 1 1 | 
             
            module Forester
         | 
| 2 2 | 
             
              module Aggregators
         | 
| 3 3 |  | 
| 4 | 
            +
                def own_and_descendants(options = {})
         | 
| 5 | 
            +
                  default_options = {
         | 
| 6 | 
            +
                    field: 'name',
         | 
| 7 | 
            +
                    if_field_missing: ->(c) { [] },
         | 
| 8 | 
            +
                  }
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  options = default_options.merge(options)
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  Enzymator::Aggregations::MapReduce.new(
         | 
| 13 | 
            +
                    {
         | 
| 14 | 
            +
                      mapping:     ->(node) { Array(node.get(options[:field], &options[:if_field_missing])) },
         | 
| 15 | 
            +
                      #reduction:   ->(acum, values) { acum.concat(values) },
         | 
| 16 | 
            +
                      #empty: []
         | 
| 17 | 
            +
                      # automatically assumed
         | 
| 18 | 
            +
                    }
         | 
| 19 | 
            +
                  )
         | 
| 20 | 
            +
                  .run_on(self)
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 4 23 | 
             
                def values_by_subtree_of_level(options = {})
         | 
| 5 24 | 
             
                  default_options = {
         | 
| 6 25 | 
             
                    level:                    1,
         | 
| 7 26 | 
             
                    group_field:              'name',
         | 
| 8 27 | 
             
                    aggregation_field:        'value',
         | 
| 9 | 
            -
                    if_field_missing:          | 
| 28 | 
            +
                    if_field_missing:         ->(c) { [] },
         | 
| 10 29 | 
             
                    include_ancestry_in_keys: false, # if false, with_root is ignored
         | 
| 11 30 | 
             
                    with_root:                false,
         | 
| 12 31 | 
             
                  }
         | 
| 13 32 |  | 
| 14 33 | 
             
                  options = default_options.merge(options)
         | 
| 15 34 |  | 
| 16 | 
            -
                   | 
| 17 | 
            -
                    null_result:       lambda { Hash.new },
         | 
| 18 | 
            -
                    initial_clusters:  lambda { |tree| tree.nodes_of_level(options[:level]) },
         | 
| 19 | 
            -
                    map:               lambda do |node|
         | 
| 20 | 
            -
                                          key_nodes = if options[:include_ancestry_in_keys]
         | 
| 21 | 
            -
                                                        node.ancestry(options[:with_root], true)
         | 
| 22 | 
            -
                                                      else
         | 
| 23 | 
            -
                                                        [node]
         | 
| 24 | 
            -
                                                      end
         | 
| 25 | 
            -
                                          key = key_nodes.map { |kn| kn.get(options[:group_field]) { |n| n.object_id } }
         | 
| 26 | 
            -
                                          key = key.first if key.one?
         | 
| 27 | 
            -
                                          key
         | 
| 28 | 
            -
                                        end,
         | 
| 29 | 
            -
                    enumerator:        lambda { |level| level.each_node },
         | 
| 30 | 
            -
                    map_each:          lambda { |node| node.get(options[:aggregation_field], &options[:if_field_missing]) },
         | 
| 31 | 
            -
                    reduce_each:       lambda { |acum, value| Array(acum).concat(Array(value)) },
         | 
| 32 | 
            -
                    reduce:            lambda { |prev, group, result| prev.merge( { group => result } ) },
         | 
| 35 | 
            +
                  input = nodes_of_level(options[:level])
         | 
| 33 36 |  | 
| 34 | 
            -
                   | 
| 37 | 
            +
                  Enzymator::Aggregations::MapReduce.new({
         | 
| 38 | 
            +
                    mapping: ->(node) {
         | 
| 35 39 |  | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 40 | 
            +
                      key_nodes = if options[:include_ancestry_in_keys]
         | 
| 41 | 
            +
                                    node.ancestry(options[:with_root], true)
         | 
| 42 | 
            +
                                  else
         | 
| 43 | 
            +
                                    [node]
         | 
| 44 | 
            +
                                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                      key = key_nodes.map { |kn| kn.get(options[:group_field]) { |n| n.object_id } }
         | 
| 47 | 
            +
                      key = key.first if key.one?
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                      value = node.own_and_descendants(
         | 
| 50 | 
            +
                        {
         | 
| 51 | 
            +
                          field: options[:aggregation_field],
         | 
| 52 | 
            +
                          if_field_missing: options[:if_field_missing]
         | 
| 53 | 
            +
                        }
         | 
| 54 | 
            +
                      )
         | 
| 38 55 |  | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 56 | 
            +
                      { key => value }
         | 
| 57 | 
            +
                    },
         | 
| 58 | 
            +
                    # reduction: ->(acum, hash) { acum.merge(hash) }
         | 
| 59 | 
            +
                    # empty: {}
         | 
| 60 | 
            +
                    # automatically assumed
         | 
| 61 | 
            +
                  }).run_on(input)
         | 
| 41 62 | 
             
                end
         | 
| 42 63 |  | 
| 43 64 | 
             
              end
         | 
    
        data/lib/forester/tree_node.rb
    CHANGED
    
    | @@ -28,6 +28,37 @@ module Forester | |
| 28 28 | 
             
                  end
         | 
| 29 29 | 
             
                end
         | 
| 30 30 |  | 
| 31 | 
            +
                def values_by_field(options)
         | 
| 32 | 
            +
                  default_options = {
         | 
| 33 | 
            +
                    field_to_search: 'name',
         | 
| 34 | 
            +
                    search_keyword: :missing_search_keyword,
         | 
| 35 | 
            +
                    values_key: :missing_values_key,
         | 
| 36 | 
            +
                    include_descendants: false,
         | 
| 37 | 
            +
                    assume_uniqueness: false
         | 
| 38 | 
            +
                  }
         | 
| 39 | 
            +
                  options = default_options.merge(options)
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  found_nodes = nodes_with(options[:field_to_search], options[:search_keyword])
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  # When assuming that node names are unique,
         | 
| 44 | 
            +
                  # if more than one node was found,
         | 
| 45 | 
            +
                  # discard all but the first one
         | 
| 46 | 
            +
                  found_nodes = found_nodes.slice(0, 1) if options[:assume_uniqueness]
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  found_nodes.flat_map do |node|
         | 
| 49 | 
            +
                    if options[:include_descendants]
         | 
| 50 | 
            +
                      node.own_and_descendants({ field: options[:values_key] })
         | 
| 51 | 
            +
                    else
         | 
| 52 | 
            +
                      node.get(options[:values_key])
         | 
| 53 | 
            +
                    end
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                def nodes_with(content_key, content_value)
         | 
| 59 | 
            +
                  each_node.select { |node| Array(node.get(content_key) { :no_match }).include? content_value }
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 31 62 | 
             
                def get(field, &block)
         | 
| 32 63 | 
             
                  content.public_send(field, &block)
         | 
| 33 64 | 
             
                end
         | 
    
        data/lib/forester/version.rb
    CHANGED
    
    
    
        data/test/test_treenode.rb
    CHANGED
    
    | @@ -30,6 +30,46 @@ class TreeNodeTest < Minitest::Test | |
| 30 30 | 
             
                aggregation_result = tree.values_by_subtree_of_level(level: 2, aggregation_field: 'strings', include_ancestry_in_keys: true)
         | 
| 31 31 |  | 
| 32 32 | 
             
                assert_equal expected, aggregation_result
         | 
| 33 | 
            +
             | 
| 34 | 
            +
             | 
| 35 | 
            +
                expected_value = [7]
         | 
| 36 | 
            +
                actual_value = tree.values_by_field({
         | 
| 37 | 
            +
                  field_to_search: 'name',
         | 
| 38 | 
            +
                  search_keyword: 'Second node of level 3',
         | 
| 39 | 
            +
                  values_key: 'value'
         | 
| 40 | 
            +
                })
         | 
| 41 | 
            +
                assert_equal expected_value, actual_value
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                expected_values = [7, 8, 9]
         | 
| 44 | 
            +
                actual_values = tree.values_by_field({
         | 
| 45 | 
            +
                  field_to_search: 'name',
         | 
| 46 | 
            +
                  search_keyword: 'Second node of level 3',
         | 
| 47 | 
            +
                  values_key: 'value',
         | 
| 48 | 
            +
                  include_descendants: true
         | 
| 49 | 
            +
                })
         | 
| 50 | 
            +
                assert_equal expected_values, actual_values
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                expected_value = [7]
         | 
| 53 | 
            +
                actual_value = tree.values_by_field({
         | 
| 54 | 
            +
                  field_to_search: 'strings',
         | 
| 55 | 
            +
                  search_keyword: 'A hidden secret lies in the deepest leaves...',
         | 
| 56 | 
            +
                  values_key: 'value'
         | 
| 57 | 
            +
                })
         | 
| 58 | 
            +
                assert_equal expected_value, actual_value
         | 
| 59 | 
            +
             | 
| 60 | 
            +
             | 
| 61 | 
            +
                expected_names = ["A hidden secret lies in the deepest leaves...", "Just kidding.", "Could forester handle trees with hundreds of levels?", "Maybe."]
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                found_nodes = tree.nodes_with('name', 'Second node of level 3')
         | 
| 64 | 
            +
                assert_equal 1, found_nodes.length
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                actual_names = found_nodes.flat_map do |node|
         | 
| 67 | 
            +
                  node.own_and_descendants({
         | 
| 68 | 
            +
                    field: 'strings'
         | 
| 69 | 
            +
                  })
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                assert_equal expected_names, actual_names
         | 
| 33 73 | 
             
              end
         | 
| 34 74 |  | 
| 35 75 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,83 +1,83 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: forester
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0 | 
| 4 | 
            +
              version: 0.1.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Eugenio Bruno
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2016-07- | 
| 11 | 
            +
            date: 2016-07-24 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: rubytree
         | 
| 15 15 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 16 | 
             
                requirements:
         | 
| 17 | 
            -
                - -  | 
| 17 | 
            +
                - - '='
         | 
| 18 18 | 
             
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            -
                    version:  | 
| 19 | 
            +
                    version: 0.9.7
         | 
| 20 20 | 
             
              type: :runtime
         | 
| 21 21 | 
             
              prerelease: false
         | 
| 22 22 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 23 | 
             
                requirements:
         | 
| 24 | 
            -
                - -  | 
| 24 | 
            +
                - - '='
         | 
| 25 25 | 
             
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            -
                    version:  | 
| 26 | 
            +
                    version: 0.9.7
         | 
| 27 27 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 28 28 | 
             
              name: enzymator
         | 
| 29 29 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 30 | 
             
                requirements:
         | 
| 31 | 
            -
                - -  | 
| 31 | 
            +
                - - '='
         | 
| 32 32 | 
             
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            -
                    version:  | 
| 33 | 
            +
                    version: 1.0.0
         | 
| 34 34 | 
             
              type: :runtime
         | 
| 35 35 | 
             
              prerelease: false
         | 
| 36 36 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 37 | 
             
                requirements:
         | 
| 38 | 
            -
                - -  | 
| 38 | 
            +
                - - '='
         | 
| 39 39 | 
             
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            -
                    version:  | 
| 40 | 
            +
                    version: 1.0.0
         | 
| 41 41 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 42 42 | 
             
              name: rake
         | 
| 43 43 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 44 | 
             
                requirements:
         | 
| 45 | 
            -
                - - ~>
         | 
| 45 | 
            +
                - - "~>"
         | 
| 46 46 | 
             
                  - !ruby/object:Gem::Version
         | 
| 47 47 | 
             
                    version: '11.2'
         | 
| 48 48 | 
             
              type: :development
         | 
| 49 49 | 
             
              prerelease: false
         | 
| 50 50 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 51 | 
             
                requirements:
         | 
| 52 | 
            -
                - - ~>
         | 
| 52 | 
            +
                - - "~>"
         | 
| 53 53 | 
             
                  - !ruby/object:Gem::Version
         | 
| 54 54 | 
             
                    version: '11.2'
         | 
| 55 55 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 56 56 | 
             
              name: minitest
         | 
| 57 57 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 58 | 
             
                requirements:
         | 
| 59 | 
            -
                - - ~>
         | 
| 59 | 
            +
                - - "~>"
         | 
| 60 60 | 
             
                  - !ruby/object:Gem::Version
         | 
| 61 61 | 
             
                    version: '5.9'
         | 
| 62 62 | 
             
              type: :development
         | 
| 63 63 | 
             
              prerelease: false
         | 
| 64 64 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 65 | 
             
                requirements:
         | 
| 66 | 
            -
                - - ~>
         | 
| 66 | 
            +
                - - "~>"
         | 
| 67 67 | 
             
                  - !ruby/object:Gem::Version
         | 
| 68 68 | 
             
                    version: '5.9'
         | 
| 69 69 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 70 70 | 
             
              name: pry-byebug
         | 
| 71 71 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 72 72 | 
             
                requirements:
         | 
| 73 | 
            -
                - - ~>
         | 
| 73 | 
            +
                - - "~>"
         | 
| 74 74 | 
             
                  - !ruby/object:Gem::Version
         | 
| 75 75 | 
             
                    version: '3.4'
         | 
| 76 76 | 
             
              type: :development
         | 
| 77 77 | 
             
              prerelease: false
         | 
| 78 78 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 79 79 | 
             
                requirements:
         | 
| 80 | 
            -
                - - ~>
         | 
| 80 | 
            +
                - - "~>"
         | 
| 81 81 | 
             
                  - !ruby/object:Gem::Version
         | 
| 82 82 | 
             
                    version: '3.4'
         | 
| 83 83 | 
             
            description: Based on rubytree and enzymator, this gem lets you build trees and run
         | 
| @@ -112,17 +112,17 @@ require_paths: | |
| 112 112 | 
             
            - lib
         | 
| 113 113 | 
             
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 114 114 | 
             
              requirements:
         | 
| 115 | 
            -
              - -  | 
| 115 | 
            +
              - - ">="
         | 
| 116 116 | 
             
                - !ruby/object:Gem::Version
         | 
| 117 | 
            -
                  version:  | 
| 117 | 
            +
                  version: 2.0.0
         | 
| 118 118 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 119 119 | 
             
              requirements:
         | 
| 120 | 
            -
              - -  | 
| 120 | 
            +
              - - ">="
         | 
| 121 121 | 
             
                - !ruby/object:Gem::Version
         | 
| 122 122 | 
             
                  version: '0'
         | 
| 123 123 | 
             
            requirements: []
         | 
| 124 124 | 
             
            rubyforge_project: 
         | 
| 125 | 
            -
            rubygems_version: 2. | 
| 125 | 
            +
            rubygems_version: 2.5.1
         | 
| 126 126 | 
             
            signing_key: 
         | 
| 127 127 | 
             
            specification_version: 4
         | 
| 128 128 | 
             
            summary: A gem to represent and interact with tree data structures
         |