abstract_mapper 0.0.2 → 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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +0 -4
  3. data/CHANGELOG.md +26 -0
  4. data/README.md +5 -5
  5. data/Rakefile +1 -1
  6. data/abstract_mapper.gemspec +1 -0
  7. data/lib/abstract_mapper.rb +4 -15
  8. data/lib/abstract_mapper/ast.rb +16 -0
  9. data/lib/abstract_mapper/ast/branch.rb +121 -0
  10. data/lib/abstract_mapper/ast/node.rb +91 -0
  11. data/lib/abstract_mapper/builder.rb +2 -2
  12. data/lib/abstract_mapper/commands.rb +4 -2
  13. data/lib/abstract_mapper/commands/base.rb +69 -0
  14. data/lib/abstract_mapper/dsl.rb +2 -2
  15. data/lib/abstract_mapper/errors.rb +17 -0
  16. data/lib/abstract_mapper/errors/wrong_node.rb +1 -1
  17. data/lib/abstract_mapper/errors/wrong_rule.rb +1 -1
  18. data/lib/abstract_mapper/optimizer.rb +1 -1
  19. data/lib/abstract_mapper/rules.rb +10 -5
  20. data/lib/abstract_mapper/rules/base.rb +74 -0
  21. data/lib/abstract_mapper/rules/pair.rb +68 -0
  22. data/lib/abstract_mapper/rules/sole.rb +60 -0
  23. data/lib/abstract_mapper/settings.rb +22 -30
  24. data/lib/abstract_mapper/version.rb +1 -1
  25. data/lib/rspec/nodes.rb +2 -2
  26. data/spec/integration/faceter.rb +4 -4
  27. data/spec/integration/rspec_examples_spec.rb +0 -6
  28. data/spec/unit/abstract_mapper/{branch_spec.rb → ast/branch_spec.rb} +28 -61
  29. data/spec/unit/abstract_mapper/{node_spec.rb → ast/node_spec.rb} +16 -53
  30. data/spec/unit/abstract_mapper/builder_spec.rb +9 -24
  31. data/spec/unit/abstract_mapper/{command_spec.rb → commands/base_spec.rb} +10 -25
  32. data/spec/unit/abstract_mapper/commands_spec.rb +9 -14
  33. data/spec/unit/abstract_mapper/dsl_spec.rb +23 -15
  34. data/spec/unit/abstract_mapper/errors/unknown_command_spec.rb +1 -4
  35. data/spec/unit/abstract_mapper/errors/wrong_node_spec.rb +5 -4
  36. data/spec/unit/abstract_mapper/errors/wrong_rule_spec.rb +5 -5
  37. data/spec/unit/abstract_mapper/functions/compact_spec.rb +0 -2
  38. data/spec/unit/abstract_mapper/functions/filter_spec.rb +0 -2
  39. data/spec/unit/abstract_mapper/functions/identity_spec.rb +0 -2
  40. data/spec/unit/abstract_mapper/functions/restrict_spec.rb +0 -3
  41. data/spec/unit/abstract_mapper/functions/subclass_spec.rb +0 -2
  42. data/spec/unit/abstract_mapper/optimizer_spec.rb +13 -17
  43. data/spec/unit/abstract_mapper/{rule_spec.rb → rules/base_spec.rb} +17 -34
  44. data/spec/unit/abstract_mapper/{pair_rule_spec.rb → rules/pair_spec.rb} +8 -8
  45. data/spec/unit/abstract_mapper/{sole_rule_spec.rb → rules/sole_spec.rb} +5 -5
  46. data/spec/unit/abstract_mapper/rules_spec.rb +24 -37
  47. data/spec/unit/abstract_mapper/settings_spec.rb +38 -32
  48. data/spec/unit/abstract_mapper_spec.rb +9 -16
  49. metadata +37 -22
  50. data/lib/abstract_mapper/attributes.rb +0 -65
  51. data/lib/abstract_mapper/branch.rb +0 -120
  52. data/lib/abstract_mapper/command.rb +0 -68
  53. data/lib/abstract_mapper/node.rb +0 -87
  54. data/lib/abstract_mapper/pair_rule.rb +0 -64
  55. data/lib/abstract_mapper/rule.rb +0 -73
  56. data/lib/abstract_mapper/sole_rule.rb +0 -56
@@ -31,7 +31,7 @@ class AbstractMapper
31
31
  # @yield a block
32
32
  #
33
33
  def configure(&block)
34
- @settings = Settings.new(&block)
34
+ @settings = settings ? settings.update(&block) : Settings.new(&block)
35
35
  self
36
36
  end
37
37
 
@@ -46,7 +46,7 @@ class AbstractMapper
46
46
  private # DSL commands
47
47
 
48
48
  def tree
49
- @tree ||= Branch.new
49
+ @tree ||= AST::Branch.new
50
50
  end
51
51
 
52
52
  def respond_to_missing?(*)
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+
3
+ class AbstractMapper
4
+
5
+ # The namespace for the gem-specific exceptions
6
+ #
7
+ # @author Andrew Kozin <Andrew.Kozin@gmail.com>
8
+ #
9
+ module Errors
10
+
11
+ require_relative "errors/unknown_command"
12
+ require_relative "errors/wrong_node"
13
+ require_relative "errors/wrong_rule"
14
+
15
+ end # module Errors
16
+
17
+ end # class AbstractMapper
@@ -12,7 +12,7 @@ class AbstractMapper
12
12
 
13
13
  # @private
14
14
  def initialize(node)
15
- super "#{node} is not a subclass of AbstractMapper::Node"
15
+ super "#{node} is not a subclass of AbstractMapper::AST::Node"
16
16
  IceNine.deep_freeze(self)
17
17
  end
18
18
 
@@ -12,7 +12,7 @@ class AbstractMapper
12
12
 
13
13
  # @private
14
14
  def initialize(node)
15
- super "#{node} is not a subclass of AbstractMapper::Rule"
15
+ super "#{node} is not a subclass of AbstractMapper::Rules::Base"
16
16
  IceNine.deep_freeze(self)
17
17
  end
18
18
 
@@ -38,7 +38,7 @@ class AbstractMapper
38
38
  # @return [AbstractMapper::Branch]
39
39
  #
40
40
  def update(tree)
41
- return tree unless tree.is_a? Branch
41
+ return tree unless tree.is_a? AST::Branch
42
42
  new_tree = tree.update { rules[tree] }
43
43
  new_tree.update { new_tree.map(&method(:update)) }
44
44
  end
@@ -2,6 +2,10 @@
2
2
 
3
3
  class AbstractMapper
4
4
 
5
+ require_relative "rules/base"
6
+ require_relative "rules/sole"
7
+ require_relative "rules/pair"
8
+
5
9
  # Registry of DSL rules applicable to nodes of AST
6
10
  #
7
11
  # @api private
@@ -10,7 +14,8 @@ class AbstractMapper
10
14
 
11
15
  # @!attribute [r] registry
12
16
  #
13
- # @return [Array<AbstractMapper::SoleRule>] list of rules applicable to AST
17
+ # @return [Array<AbstractMapper::Rules::Base>]
18
+ # the list of rules applicable to AST
14
19
  #
15
20
  attr_reader :registry
16
21
 
@@ -18,7 +23,7 @@ class AbstractMapper
18
23
  # @!method new(registry)
19
24
  # Creates a registry with array of rules
20
25
  #
21
- # @param [Array<AbstractMapper::SoleRule>] registry Array of rules
26
+ # @param [Array<AbstractMapper::Rules::Base>] registry Array of rules
22
27
  #
23
28
  # @return [AbstractMapper::Rules]
24
29
 
@@ -31,7 +36,7 @@ class AbstractMapper
31
36
 
32
37
  # Returns the copy of current registry with the new rule added
33
38
  #
34
- # @param [AbstractMapper::SoleRule] other
39
+ # @param [AbstractMapper::Rules::Base] other
35
40
  #
36
41
  # @return (see #new)
37
42
  #
@@ -41,9 +46,9 @@ class AbstractMapper
41
46
 
42
47
  # Applies all the registered rules to the array of nodes
43
48
  #
44
- # @param [Array<AbstractMapper::Node>] nodes
49
+ # @param [Array<AbstractMapper::AST::Node>] nodes
45
50
  #
46
- # @return [Array<AbstractMapper::Node>] The optimized array of nodes
51
+ # @return [Array<AbstractMapper::AST::Node>] The optimized array of nodes
47
52
  #
48
53
  def [](nodes)
49
54
  @transproc ? @transproc[nodes] : nodes
@@ -0,0 +1,74 @@
1
+ # encoding: utf-8
2
+
3
+ class AbstractMapper
4
+
5
+ class Rules
6
+
7
+ # Base class for optimization rules
8
+ #
9
+ # @abstract
10
+ #
11
+ # @api private
12
+ #
13
+ class Base
14
+
15
+ # @private
16
+ def self.composer
17
+ :identity
18
+ end
19
+ private_class_method :composer
20
+
21
+ # The transformation function that applies the rule to the array of nodes
22
+ #
23
+ # @return [Transproc::Function]
24
+ #
25
+ def self.transproc
26
+ Functions[composer, proc { |*nodes| new(*nodes).call }]
27
+ end
28
+
29
+ # @!attribute [r] nodes
30
+ #
31
+ # @return [Array<AbstractMapper::AST::Node>]
32
+ # Either one or two nodes to be optimized
33
+ #
34
+ attr_reader :nodes
35
+
36
+ # Initializes the rule for a sole node, or a pair of consecutive nodes
37
+ #
38
+ # @param [Array<AbstractMapper::AST::Node>] nodes
39
+ #
40
+ # @return [AbstractMapper::Rules::Base]
41
+ #
42
+ def initialize(*nodes)
43
+ @nodes = nodes
44
+ IceNine.deep_freeze(self)
45
+ end
46
+
47
+ # Checks if optimization is needed for the node(s)
48
+ #
49
+ # @return [Boolean]
50
+ #
51
+ def optimize?
52
+ end
53
+
54
+ # Returns the optimized node(s)
55
+ #
56
+ # @return [Object]
57
+ #
58
+ def optimize
59
+ nodes
60
+ end
61
+
62
+ # Returns the result of the rule applied to the initialized [#nodes]
63
+ #
64
+ # @return [Array<AbstractMapper::AST::Node>]
65
+ #
66
+ def call
67
+ optimize? ? [optimize].flatten.compact : nodes
68
+ end
69
+
70
+ end # class Base
71
+
72
+ end # class Rules
73
+
74
+ end # class AbstractMapper
@@ -0,0 +1,68 @@
1
+ # encoding: utf-8
2
+
3
+ class AbstractMapper
4
+
5
+ class Rules
6
+
7
+ # The base class for rules to be applied to pairs of nodes.
8
+ #
9
+ # The subclass should implement two instance methods:
10
+ #
11
+ # * `#optimize?` to check if the optimization should be applied to the nodes
12
+ # * `#optimize` that should return the merged node
13
+ #
14
+ # @example
15
+ # class MergeConsecutiveLists < AbstractMapper::Rules::Pair
16
+ # def optimize?
17
+ # left.is_a?(List) & right.is_a?(List)
18
+ # end
19
+ #
20
+ # def optimize
21
+ # List.new { left.entries + right.entries }
22
+ # end
23
+ # end
24
+ #
25
+ # @abstract
26
+ #
27
+ # @api public
28
+ #
29
+ class Pair < Base
30
+
31
+ # @private
32
+ def self.composer
33
+ :compact
34
+ end
35
+ private_class_method :composer
36
+
37
+ # @!attribute [r] node
38
+ #
39
+ # @return [AbstractMapper::AST::Node] The left node in the pair
40
+ #
41
+ attr_reader :left
42
+
43
+ # @!attribute [r] node
44
+ #
45
+ # @return [AbstractMapper::AST::Node] The right node in the pair
46
+ #
47
+ attr_reader :right
48
+
49
+ # @!scope class
50
+ # @!method new(node)
51
+ # Creates a rule applied to the sole node
52
+ #
53
+ # @param [AbstractMapper::AST::Node] node
54
+ #
55
+ # @return [AbstractMapper::Rules::Base]
56
+
57
+ # @private
58
+ def initialize(left, right)
59
+ @left = left
60
+ @right = right
61
+ super
62
+ end
63
+
64
+ end # class Pair
65
+
66
+ end # class Rule
67
+
68
+ end # class AbstractMapper
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+
3
+ class AbstractMapper
4
+
5
+ class Rules
6
+
7
+ # The abstract class that describes the rule to be applied to sole nodes.
8
+ #
9
+ # The subclass should implement two instance methods:
10
+ #
11
+ # * `#optimize?` to check if the optimization should be applied to the node
12
+ # * `#optimize` that should return the optimized node
13
+ #
14
+ # @example
15
+ # class RemoveEmptyList < AbstractMapper::Rules::Sole
16
+ # def optimize?
17
+ # node.is_a?(List) && node.empty?
18
+ # end
19
+ #
20
+ # def optimize
21
+ # end
22
+ # end
23
+ #
24
+ # @abstract
25
+ #
26
+ # @api public
27
+ #
28
+ class Sole < Base
29
+
30
+ # @private
31
+ def self.composer
32
+ :filter
33
+ end
34
+ private_class_method :composer
35
+
36
+ # @!attribute [r] node
37
+ #
38
+ # @return [AbstractMapper::AST::Node] The node to be optimized
39
+ #
40
+ attr_reader :node
41
+
42
+ # @!scope class
43
+ # @!method new(node)
44
+ # Creates a rule applied to the sole node
45
+ #
46
+ # @param [AbstractMapper::AST::Node] node
47
+ #
48
+ # @return [AbstractMapper::Rules::Base]
49
+
50
+ # @private
51
+ def initialize(node)
52
+ @node = node
53
+ super
54
+ end
55
+
56
+ end # class Sole
57
+
58
+ end # class Rule
59
+
60
+ end # class AbstractMapper
@@ -36,57 +36,49 @@ class AbstractMapper
36
36
  #
37
37
  attr_reader :builder
38
38
 
39
- # @!scope class
40
- # @!method new(&block)
41
- # Creates a domain-specific settings with commands and rules initialized
42
- # from inside a block
39
+ # Initializes a domain-specific settings with commands and rules
40
+ # being set in the block.
43
41
  #
44
42
  # @param [Proc] block
45
43
  #
46
- # @return [AbstractMapper::Settings]
47
-
48
- # @private
49
- def initialize(&block)
50
- __set_rules__
51
- __set_commands__
52
- __configure__(&block)
53
- __set_builder__
54
- __set_optimizer__
44
+ # @yield the block with settings for commands and rules
45
+ #
46
+ def initialize(rules = Rules.new, commands = Commands.new, &block)
47
+ @rules = rules
48
+ @commands = commands
49
+ configure(&block)
55
50
  IceNine.deep_freeze(self)
56
51
  end
57
52
 
53
+ # Returns a new class with rules and commands added from the block
54
+ # to the existing ones
55
+ #
56
+ # @return [AbstractMapper::Settings]
57
+ #
58
+ # @yield the block with settings for commands and rules
59
+ #
60
+ def update(&block)
61
+ self.class.new(rules, commands, &block)
62
+ end
63
+
58
64
  private
59
65
 
60
66
  def rule(value)
61
- fn = Functions[:subclass?, Rule]
67
+ fn = Functions[:subclass?, Rules::Base]
62
68
  fail Errors::WrongRule.new(value) unless fn[value]
63
69
  @rules = rules << value
64
70
  end
65
71
 
66
72
  def command(name, node, &block)
67
- fn = Functions[:subclass?, Node]
73
+ fn = Functions[:subclass?, AST::Node]
68
74
  fail Errors::WrongNode.new(node) unless fn[node]
69
75
  @commands = commands << [name, node, block]
70
76
  end
71
77
 
72
- def __set_rules__
73
- @rules = Rules.new
74
- end
75
-
76
- def __set_commands__
77
- @commands = Commands.new
78
- end
79
-
80
- def __configure__(&block)
78
+ def configure(&block)
81
79
  instance_eval(&block) if block_given?
82
- end
83
-
84
- def __set_builder__
85
80
  @builder = Class.new(Builder)
86
81
  builder.commands = commands
87
- end
88
-
89
- def __set_optimizer__
90
82
  @optimizer = Optimizer.new(rules)
91
83
  end
92
84
 
@@ -4,6 +4,6 @@ class AbstractMapper
4
4
 
5
5
  # The semantic version of the module.
6
6
  # @see http://semver.org/ Semantic versioning 2.0
7
- VERSION = "0.0.2".freeze
7
+ VERSION = "0.1.0".freeze
8
8
 
9
9
  end # class AbstractMapper
@@ -20,7 +20,7 @@ shared_examples :creating_immutable_node do
20
20
 
21
21
  subject { node }
22
22
 
23
- it { is_expected.to be_kind_of AbstractMapper::Node }
23
+ it { is_expected.to be_kind_of AbstractMapper::AST::Node }
24
24
  it { is_expected.to be_frozen, "expected #{subject.inspect} to be immutable" }
25
25
 
26
26
  end # shared examples
@@ -31,7 +31,7 @@ shared_examples :creating_immutable_branch do
31
31
 
32
32
  subject { node }
33
33
 
34
- it { is_expected.to be_kind_of AbstractMapper::Branch }
34
+ it { is_expected.to be_kind_of AbstractMapper::AST::Branch }
35
35
  it { is_expected.to be_frozen, "expected #{subject.inspect} to be immutable" }
36
36
 
37
37
  end # shared examples
@@ -14,13 +14,13 @@ shared_context "Faceter" do
14
14
  end
15
15
 
16
16
  # Nodes
17
- class List < AbstractMapper::Branch
17
+ class List < AbstractMapper::AST::Branch
18
18
  def transproc
19
19
  Functions[:map_array, super]
20
20
  end
21
21
  end
22
22
 
23
- class Rename < AbstractMapper::Node
23
+ class Rename < AbstractMapper::AST::Node
24
24
  attribute :keys
25
25
 
26
26
  def transproc
@@ -29,7 +29,7 @@ shared_context "Faceter" do
29
29
  end
30
30
 
31
31
  # Rules
32
- class CompactLists < AbstractMapper::PairRule
32
+ class CompactLists < AbstractMapper::Rules::Pair
33
33
  def optimize?
34
34
  left.is_a?(List) && right.is_a?(List)
35
35
  end
@@ -39,7 +39,7 @@ shared_context "Faceter" do
39
39
  end
40
40
  end
41
41
 
42
- class CompactRenames < AbstractMapper::PairRule
42
+ class CompactRenames < AbstractMapper::Rules::Pair
43
43
  def optimize?
44
44
  left.is_a?(Rename) && right.is_a?(Rename)
45
45
  end