abstract_mapper 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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