forester 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 419a779f1ffc62fb2fea36308c2c9b92a0a2474a
4
- data.tar.gz: 19572a329a088ccd53d41480c929c2e6ee62ac21
3
+ metadata.gz: ca08cece8313d3e3c8b20bae94f78163b81853cb
4
+ data.tar.gz: d6b07a8b064d28e35b302a9999f5c45b8a0bcdb2
5
5
  SHA512:
6
- metadata.gz: 0fc4a63df68429492ef84ed56d819ba617fa8337f9feb9d77e2d92de78d077b1c47ccda3923d1db333eebe0bedb15379e54f6a9d4901612df5e49aa9d5e7ecd3
7
- data.tar.gz: bbbb7a95d5a061d35bdec80ae1679d4eb929106e10ae5549590974e6f9f050344919dc9a0f804c402657fe0255f877dcf3fc3163526608ad154841cb642cf4da
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-19'
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 = '>= 1.9.2'
22
+ s.required_ruby_version = '>= 2.0.0'
23
23
 
24
- s.add_runtime_dependency 'rubytree', ['~> 0.9']
25
- s.add_runtime_dependency 'enzymator', ['~> 0.0']
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']
@@ -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: lambda { |c| [] },
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
- aggregation_config = {
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
- aggregated(aggregation_config, options)
37
- end
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
- def aggregated(config, options = {})
40
- Enzymator::Aggregation.new(config).run_on(self, options)
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
@@ -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
@@ -1,13 +1,12 @@
1
1
  module Forester
2
2
  class Version
3
3
  MAJOR = 0
4
- MINOR = 0
5
- PATCH = 4
4
+ MINOR = 1
5
+ PATCH = 0
6
6
  PRE = nil
7
7
 
8
8
  class << self
9
9
 
10
- # @return [String]
11
10
  def to_s
12
11
  [MAJOR, MINOR, PATCH, PRE].compact.join('.')
13
12
  end
@@ -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
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-19 00:00:00.000000000 Z
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: '0.9'
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: '0.9'
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: '0.0'
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: '0.0'
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: 1.9.2
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.4.8
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