faceter 0.0.1

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.
Files changed (125) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +2 -0
  3. data/.gitignore +9 -0
  4. data/.metrics +9 -0
  5. data/.rspec +2 -0
  6. data/.rubocop.yml +2 -0
  7. data/.travis.yml +18 -0
  8. data/.yardopts +3 -0
  9. data/CHANGELOG.md +3 -0
  10. data/Gemfile +9 -0
  11. data/Guardfile +10 -0
  12. data/LICENSE +21 -0
  13. data/README.md +295 -0
  14. data/Rakefile +37 -0
  15. data/benchmark/data.json +1 -0
  16. data/benchmark/faceter.rb +73 -0
  17. data/benchmark/rom.rb +85 -0
  18. data/benchmark/run.rb +54 -0
  19. data/config/metrics/STYLEGUIDE +230 -0
  20. data/config/metrics/cane.yml +5 -0
  21. data/config/metrics/churn.yml +6 -0
  22. data/config/metrics/flay.yml +2 -0
  23. data/config/metrics/metric_fu.yml +14 -0
  24. data/config/metrics/reek.yml +1 -0
  25. data/config/metrics/roodi.yml +24 -0
  26. data/config/metrics/rubocop.yml +75 -0
  27. data/config/metrics/saikuro.yml +3 -0
  28. data/config/metrics/simplecov.yml +6 -0
  29. data/config/metrics/yardstick.yml +37 -0
  30. data/faceter.gemspec +29 -0
  31. data/lib/faceter.rb +54 -0
  32. data/lib/faceter/coercers.rb +68 -0
  33. data/lib/faceter/functions.rb +30 -0
  34. data/lib/faceter/functions/add_prefix.rb +25 -0
  35. data/lib/faceter/functions/claster.rb +27 -0
  36. data/lib/faceter/functions/clean.rb +27 -0
  37. data/lib/faceter/functions/drop_prefix.rb +29 -0
  38. data/lib/faceter/functions/exclude.rb +27 -0
  39. data/lib/faceter/functions/group.rb +41 -0
  40. data/lib/faceter/functions/keep_symbol.rb +27 -0
  41. data/lib/faceter/functions/split.rb +28 -0
  42. data/lib/faceter/functions/ungroup.rb +31 -0
  43. data/lib/faceter/functions/unwrap.rb +32 -0
  44. data/lib/faceter/functions/wrap.rb +32 -0
  45. data/lib/faceter/mapper.rb +38 -0
  46. data/lib/faceter/nodes/add_prefix.rb +21 -0
  47. data/lib/faceter/nodes/change_prefix.rb +51 -0
  48. data/lib/faceter/nodes/create.rb +43 -0
  49. data/lib/faceter/nodes/exclude.rb +25 -0
  50. data/lib/faceter/nodes/field.rb +25 -0
  51. data/lib/faceter/nodes/fold.rb +25 -0
  52. data/lib/faceter/nodes/group.rb +26 -0
  53. data/lib/faceter/nodes/list.rb +25 -0
  54. data/lib/faceter/nodes/remove_prefix.rb +21 -0
  55. data/lib/faceter/nodes/rename.rb +25 -0
  56. data/lib/faceter/nodes/stringify_keys.rb +26 -0
  57. data/lib/faceter/nodes/symbolize_keys.rb +26 -0
  58. data/lib/faceter/nodes/unfold.rb +25 -0
  59. data/lib/faceter/nodes/ungroup.rb +26 -0
  60. data/lib/faceter/nodes/unwrap.rb +26 -0
  61. data/lib/faceter/nodes/wrap.rb +26 -0
  62. data/lib/faceter/rules/append_nested.rb +28 -0
  63. data/lib/faceter/rules/merge_branches.rb +41 -0
  64. data/lib/faceter/rules/merge_excludes.rb +29 -0
  65. data/lib/faceter/rules/merge_renames.rb +27 -0
  66. data/lib/faceter/rules/order_fields.rb +27 -0
  67. data/lib/faceter/rules/prepend_nested.rb +51 -0
  68. data/lib/faceter/version.rb +11 -0
  69. data/spec/integration/commands/add_prefix_spec.rb +37 -0
  70. data/spec/integration/commands/create_spec.rb +33 -0
  71. data/spec/integration/commands/exclude_spec.rb +55 -0
  72. data/spec/integration/commands/fold_spec.rb +41 -0
  73. data/spec/integration/commands/group_spec.rb +64 -0
  74. data/spec/integration/commands/remove_prefix_spec.rb +63 -0
  75. data/spec/integration/commands/rename_spec.rb +45 -0
  76. data/spec/integration/commands/stringify_keys_spec.rb +65 -0
  77. data/spec/integration/commands/symbolize_keys_spec.rb +49 -0
  78. data/spec/integration/commands/unfold_spec.rb +41 -0
  79. data/spec/integration/commands/ungroup_spec.rb +64 -0
  80. data/spec/integration/commands/unwrap_spec.rb +51 -0
  81. data/spec/integration/commands/wrap_spec.rb +51 -0
  82. data/spec/integration/rom_spec.rb +39 -0
  83. data/spec/spec_helper.rb +25 -0
  84. data/spec/unit/coercers/create_spec.rb +16 -0
  85. data/spec/unit/coercers/exclude_spec.rb +31 -0
  86. data/spec/unit/coercers/field_spec.rb +11 -0
  87. data/spec/unit/coercers/fold_spec.rb +11 -0
  88. data/spec/unit/coercers/prefix_spec.rb +38 -0
  89. data/spec/unit/coercers/rename_spec.rb +11 -0
  90. data/spec/unit/coercers/unfold_spec.rb +11 -0
  91. data/spec/unit/coercers/unwrap_spec.rb +35 -0
  92. data/spec/unit/coercers/wrap_spec.rb +35 -0
  93. data/spec/unit/functions/add_prefix_spec.rb +12 -0
  94. data/spec/unit/functions/claster_spec.rb +12 -0
  95. data/spec/unit/functions/clean_spec.rb +18 -0
  96. data/spec/unit/functions/drop_prefix_spec.rb +33 -0
  97. data/spec/unit/functions/exclude_spec.rb +64 -0
  98. data/spec/unit/functions/group_spec.rb +176 -0
  99. data/spec/unit/functions/keep_symbol_spec.rb +21 -0
  100. data/spec/unit/functions/split_spec.rb +64 -0
  101. data/spec/unit/functions/ungroup_spec.rb +87 -0
  102. data/spec/unit/functions/unwrap_spec.rb +54 -0
  103. data/spec/unit/functions/wrap_spec.rb +67 -0
  104. data/spec/unit/nodes/add_prefix_spec.rb +62 -0
  105. data/spec/unit/nodes/create_spec.rb +53 -0
  106. data/spec/unit/nodes/exclude_spec.rb +18 -0
  107. data/spec/unit/nodes/field_spec.rb +30 -0
  108. data/spec/unit/nodes/fold_spec.rb +19 -0
  109. data/spec/unit/nodes/group_spec.rb +163 -0
  110. data/spec/unit/nodes/list_spec.rb +27 -0
  111. data/spec/unit/nodes/remove_prefix_spec.rb +62 -0
  112. data/spec/unit/nodes/rename_spec.rb +16 -0
  113. data/spec/unit/nodes/stringify_keys_spec.rb +21 -0
  114. data/spec/unit/nodes/symbolize_keys_spec.rb +21 -0
  115. data/spec/unit/nodes/unfold_spec.rb +19 -0
  116. data/spec/unit/nodes/ungroup_spec.rb +92 -0
  117. data/spec/unit/nodes/unwrap_spec.rb +47 -0
  118. data/spec/unit/nodes/wrap_spec.rb +33 -0
  119. data/spec/unit/rules/append_nested_spec.rb +41 -0
  120. data/spec/unit/rules/merge_branches_spec.rb +58 -0
  121. data/spec/unit/rules/merge_excludes_spec.rb +31 -0
  122. data/spec/unit/rules/merge_renames_spec.rb +29 -0
  123. data/spec/unit/rules/order_fields_spec.rb +31 -0
  124. data/spec/unit/rules/prepend_nested_spec.rb +41 -0
  125. metadata +315 -0
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+
3
+ module Faceter
4
+
5
+ module Functions
6
+
7
+ # Removes the prefix with separator from the string
8
+ #
9
+ # @example
10
+ # fn = Functions[:drop_prefix, "foo", "."]
11
+ # fn["foo.bar"] # => "bar"
12
+ #
13
+ # @param [#to_s] string
14
+ # @param [#to_s] prefix
15
+ # @param [#to_sl] separator
16
+ #
17
+ # @return [String]
18
+ #
19
+ def self.drop_prefix(string, prefix, separator)
20
+ str = string.to_s
21
+ affix = "#{prefix}#{separator}"
22
+ first = str.start_with?(affix) ? affix.length : 0
23
+
24
+ str[first..-1]
25
+ end
26
+
27
+ end # module Functions
28
+
29
+ end # module Faceter
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+
3
+ module Faceter
4
+
5
+ module Functions
6
+
7
+ # Excludes keys, that satisfies the selector, from the hash
8
+ #
9
+ # @example
10
+ # selector = Selector.new(only: /b/)
11
+ # function = Functions[:exclude, selector]
12
+ #
13
+ # function[{ foo: :FOO, bar: :BAR, baz: :BAZ }]
14
+ # # => { foo: :FOO }
15
+ #
16
+ # @param [Hash] hash
17
+ # @param [Selector::Condition] selector
18
+ #
19
+ # @return [Array<Hash>]
20
+ #
21
+ def self.exclude(hash, selector)
22
+ hash.reject { |key| selector[key] }
23
+ end
24
+
25
+ end # module Functions
26
+
27
+ end # module Faceter
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ module Faceter
4
+
5
+ module Functions
6
+
7
+ # Groups array values using provided root key and selector
8
+ #
9
+ # @example
10
+ # selector = Selector.new(only: [:bar])
11
+ # function = Functions[:group, :qux, selector]
12
+ #
13
+ # function[[{ foo: :FOO, bar: :BAR }, { foo: :FOO, bar: :BAZ }]]
14
+ # # => [{ foo: :FOO, qux: [{ bar: :BAR }, { bar: :BAZ }] }]
15
+ #
16
+ # @param [Array] array
17
+ # @param [Object] key
18
+ # @param [Selector::Condition] selector
19
+ #
20
+ # @return [Array<Hash>]
21
+ #
22
+ def self.group(array, key, selector)
23
+ tuples = Hash.new { |h, k| h[k] = [] }
24
+
25
+ array.each do |hash|
26
+ to_group, to_keep = split(Hash[hash], selector)
27
+ grouped = t(:to_tuples)[to_keep[key]]
28
+ to_keep.delete(key)
29
+
30
+ tuples[to_keep] << grouped.map { |item| item.merge(to_group) }
31
+ end
32
+
33
+ tuples.map do |root, children|
34
+ list = children.flatten
35
+ list.first.empty? ? root : root.merge(key => list)
36
+ end
37
+ end
38
+
39
+ end # module Functions
40
+
41
+ end # module Faceter
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+
3
+ module Faceter
4
+
5
+ module Functions
6
+
7
+ # Applies the function to the source and converts the result to symbol
8
+ # if the source data was a symbol.
9
+ #
10
+ # @example
11
+ # fn = Functions[:keep_symbol, -> v { v.to_s.reverse }]
12
+ # fn["123"] # => "321"
13
+ # fn[:123] # => :321
14
+ #
15
+ # @param [Object] source
16
+ # @param [Transproc::Function] fn
17
+ #
18
+ # @return [String, Symbol]
19
+ #
20
+ def self.keep_symbol(source, fn)
21
+ data = fn.call(source)
22
+ source.instance_of?(Symbol) ? data.to_s.to_sym : data
23
+ end
24
+
25
+ end # module Functions
26
+
27
+ end # module Faceter
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+
3
+ module Faceter
4
+
5
+ module Functions
6
+
7
+ # Splits the hash into two parts using a selector
8
+ #
9
+ # @example
10
+ # selector = Selector.new(except: /r/)
11
+ # function = Functions[:split, selector]
12
+ #
13
+ # function[{ foo: :FOO, bar: :BAR, baz: :BAZ }]
14
+ # # => [{ foo: :FOO, baz: :BAZ }, { bar: :BAR }]
15
+ #
16
+ # @param [Hash] hash
17
+ # @param [Selector::Condition] selector
18
+ #
19
+ # @return [Array<Hash>]
20
+ #
21
+ def self.split(hash, selector)
22
+ fn = -> key, _ { selector[key] }
23
+ [hash.select(&fn), hash.reject(&fn)]
24
+ end
25
+
26
+ end # module Functions
27
+
28
+ end # module Faceter
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+
3
+ module Faceter
4
+
5
+ module Functions
6
+
7
+ # Ungroups array values using provided root key and selector
8
+ #
9
+ # @example
10
+ # selector = Selector.new(only: :bar)
11
+ # function = Functions[:ungroup, :qux, selector]
12
+ #
13
+ # function[[{ foo: :FOO, qux: [{ bar: :BAR }, { bar: :BAZ }] }]]
14
+ # # => [{ foo: :FOO, bar: :BAR }, { foo: :FOO, bar: :BAZ }]
15
+ #
16
+ # @param [Array] array
17
+ # @param [Object] key
18
+ # @param [Selector::Condition] selector
19
+ #
20
+ # @return [Array<Hash>]
21
+ #
22
+ def self.ungroup(array, key, selector)
23
+ array.flat_map do |hash|
24
+ list = t(:to_tuples)[hash.delete(key)]
25
+ group(list, key, !selector).map { |item| hash.merge(item) }
26
+ end
27
+ end
28
+
29
+ end # module Functions
30
+
31
+ end # module Faceter
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+
3
+ module Faceter
4
+
5
+ module Functions
6
+
7
+ # Partially unwraps a subhash under the hash key following the selector
8
+ #
9
+ # @example
10
+ # selector = Selector.new(only: :bar)
11
+ # function = Functions[:unwrap, :foo, selector]
12
+ #
13
+ # function[foo: { bar: :BAR, baz: :BAZ }, qux: :QUX]
14
+ # # => { qux: :QUX, foo: { baz: :BAZ }, bar: :BAR }
15
+ #
16
+ # @param [Hash] hash
17
+ # @param [Object] key
18
+ # @param [Selector::Condition] selector
19
+ #
20
+ # @return Hash
21
+ #
22
+ def self.unwrap(hash, key, selector)
23
+ extracted, keep = split(hash.fetch(key, {}), selector)
24
+ cleaner = Selector.new(only: key)
25
+
26
+ clean_hash = clean(hash.merge(key => keep), cleaner)
27
+ clean_hash.merge(extracted)
28
+ end
29
+
30
+ end # module Functions
31
+
32
+ end # module Faceter
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+
3
+ module Faceter
4
+
5
+ module Functions
6
+
7
+ # Partially wraps a subhash into the new key following the selector
8
+ #
9
+ # @example
10
+ # selector = Selector.new(only: :bar)
11
+ # function = Functions[:wrap, :foo, selector]
12
+ #
13
+ # function[foo: { baz: :BAZ }, bar: :BAR, qux: :QUX]
14
+ # # => { foo: { baz: :BAZ, bar: :BAR }, qux: :QUX }
15
+ #
16
+ # @param [Hash] hash
17
+ # @param [Object] key
18
+ # @param [Selector::Condition] selector
19
+ #
20
+ # @return Hash
21
+ #
22
+ def self.wrap(hash, key, selector)
23
+ to_wrap, to_keep = split(hash, selector)
24
+ wrapped = to_keep[key]
25
+
26
+ to_wrap = wrapped.merge(to_wrap) if wrapped.instance_of? Hash
27
+ to_keep.merge(key => to_wrap)
28
+ end
29
+
30
+ end # module Functions
31
+
32
+ end # module Faceter
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+
3
+ module Faceter
4
+
5
+ # The base class for mappers
6
+ #
7
+ # @api private
8
+ #
9
+ class Mapper < AbstractMapper
10
+ configure do
11
+
12
+ # List of mapper commands
13
+ command :add_prefix, Nodes::AddPrefix, &Coercers[:prefix]
14
+ command :create, Nodes::Create, &Coercers[:create]
15
+ command :exclude, Nodes::Exclude, &Coercers[:exclude]
16
+ command :field, Nodes::Field, &Coercers[:field]
17
+ command :fold, Nodes::Fold, &Coercers[:fold]
18
+ command :group, Nodes::Group, &Coercers[:wrap]
19
+ command :list, Nodes::List
20
+ command :remove_prefix, Nodes::RemovePrefix, &Coercers[:prefix]
21
+ command :rename, Nodes::Rename, &Coercers[:rename]
22
+ command :stringify_keys, Nodes::StringifyKeys
23
+ command :symbolize_keys, Nodes::SymbolizeKeys
24
+ command :unfold, Nodes::Unfold, &Coercers[:unfold]
25
+ command :ungroup, Nodes::Ungroup, &Coercers[:unwrap]
26
+ command :unwrap, Nodes::Unwrap, &Coercers[:unwrap]
27
+ command :wrap, Nodes::Wrap, &Coercers[:wrap]
28
+
29
+ # List of optimization rules
30
+ rule Rules::PrependNested
31
+ rule Rules::AppendNested
32
+ rule Rules::MergeBranches
33
+ rule Rules::MergeRenames
34
+
35
+ end
36
+ end # class Mapper
37
+
38
+ end # module Faceter
@@ -0,0 +1,21 @@
1
+ module Faceter
2
+
3
+ module Nodes
4
+
5
+ # The node describes adding prefix from tuples' keys
6
+ #
7
+ # @api private
8
+ #
9
+ class AddPrefix < ChangePrefix
10
+
11
+ private
12
+
13
+ def __operation__
14
+ :add_prefix
15
+ end
16
+
17
+ end # class AddPrefix
18
+
19
+ end # module Nodes
20
+
21
+ end # module Faceter
@@ -0,0 +1,51 @@
1
+ module Faceter
2
+
3
+ module Nodes
4
+
5
+ # The base class for prefix-manipulating nodes
6
+ #
7
+ # see [Faceter::Nodes::AddPrefix]
8
+ # see [Faceter::Nodes::RemovePrefix]
9
+ #
10
+ # @abstract
11
+ #
12
+ # @api private
13
+ #
14
+ class ChangePrefix < AbstractMapper::Node
15
+
16
+ attribute :prefix
17
+ attribute :separator, default: "_"
18
+ attribute :nested, default: false
19
+ attribute :selector
20
+
21
+ # Transformer function, defined by the node
22
+ #
23
+ # @return [Transproc::Function]
24
+ #
25
+ def transproc
26
+ return __transformation__ unless nested
27
+ Functions[:recursion, Functions[:is, Hash, __transformation__]]
28
+ end
29
+
30
+ private
31
+
32
+ def __transformation__
33
+ Functions[:map_keys, __selected__]
34
+ end
35
+
36
+ def __selected__
37
+ return __function__ unless selector
38
+ Functions[:guard, selector, __function__]
39
+ end
40
+
41
+ def __function__
42
+ Functions[:keep_symbol, Functions[__operation__, prefix, separator]]
43
+ end
44
+
45
+ # __operation__ should be defined in a specific node
46
+
47
+ end # class AddPrefix
48
+
49
+ end # module Nodes
50
+
51
+ end # module Faceter
@@ -0,0 +1,43 @@
1
+ module Faceter
2
+
3
+ module Nodes
4
+
5
+ # The node describes creating a new value from values by keys
6
+ #
7
+ # @api private
8
+ #
9
+ class Create < AbstractMapper::Node
10
+
11
+ attribute :name
12
+ attribute :keys
13
+
14
+ # Transformer function, defined by the node
15
+ #
16
+ # @return [Transproc::Function]
17
+ #
18
+ def transproc
19
+ Functions[__fn__]
20
+ end
21
+
22
+ private
23
+
24
+ def __fn__
25
+ return __proc__ unless name
26
+ -> hash { hash.merge(name => __proc__[hash]) }
27
+ end
28
+
29
+ def __proc__
30
+ return __values__ unless block
31
+ -> hash { block[*__values__[hash]] }
32
+ end
33
+
34
+ def __values__
35
+ return -> hash { hash.fetch(keys) } unless keys.instance_of?(Array)
36
+ -> hash { hash.values_at(*keys) }
37
+ end
38
+
39
+ end # class Create
40
+
41
+ end # module Nodes
42
+
43
+ end # module Faceter
@@ -0,0 +1,25 @@
1
+ module Faceter
2
+
3
+ module Nodes
4
+
5
+ # The node describes exclusion of the field from a tuple
6
+ #
7
+ # @api private
8
+ #
9
+ class Exclude < AbstractMapper::Node
10
+
11
+ attribute :selector
12
+
13
+ # Transformer function, defined by the node
14
+ #
15
+ # @return [Transproc::Function]
16
+ #
17
+ def transproc
18
+ Functions[:exclude, selector]
19
+ end
20
+
21
+ end # class Exclude
22
+
23
+ end # module Nodes
24
+
25
+ end # module Faceter
@@ -0,0 +1,25 @@
1
+ module Faceter
2
+
3
+ module Nodes
4
+
5
+ # The composed node that describes a field of tuples in input data
6
+ #
7
+ # @api private
8
+ #
9
+ class Field < AbstractMapper::Branch
10
+
11
+ attribute :key
12
+
13
+ # Builds a transproc function for the field node from its child nodes
14
+ #
15
+ # @return [Transproc::Function]
16
+ #
17
+ def transproc
18
+ Functions[:map_value, key, super]
19
+ end
20
+
21
+ end # class Field
22
+
23
+ end # module Nodes
24
+
25
+ end # module Faceter