yard-sequel 0.1.1 → 0.2.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
  SHA256:
3
- metadata.gz: 9284ee1351b6a7f96efc170c14aef164245d849790b08ace886b7e94a86c305f
4
- data.tar.gz: 5c3d39bd376f18edf52a20b4d5e729a0c52ced190435161b5a6cf6fb37dce4ad
3
+ metadata.gz: de753ba555cdc4d50a3529d696acfc430267520084be6be153350a53a7d6f0e0
4
+ data.tar.gz: a2a0b1b504e2e37dd52e484fdf8880186b13a7d7f28f4db8e11082cec38e86ec
5
5
  SHA512:
6
- metadata.gz: 846c464a14c21f7f0c415961f6ced942deb2247143a20675a8b22dd7cde9becb2ed017e7d438f538ccb6a098139695cc1fadf96fae608084c0780a9d1bc3bcc8
7
- data.tar.gz: 95a2d3e008efc2c0f6b4839465b70eaae1fc10de39cdefac228236ab3a62ebf61773314f381b3570d530a9830a45c773fc51b797cc0eb0ace075ef252ef91e58
6
+ metadata.gz: 18d50a853a958f1999996ecd350626c778a9be1c9288a37b45167927c8264e61bf5ac2521f7bf80501734dec183192cfac5d7bbcbc326f355dcf62c730810f0d
7
+ data.tar.gz: 222fcedd00f7b9be0f62ceffa307ca39ce62494447f4be0f76b86cb3ad8e13cad91c5321b0f325f5f5facc88a0d09fd73adf05352be3d10e4340630ee47a6071
data/lib/yard-sequel.rb CHANGED
@@ -10,4 +10,5 @@ Sequel.extension :inflector
10
10
  module YardSequel; end
11
11
 
12
12
  require_relative 'yard-sequel/associations'
13
+ require_relative 'yard-sequel/association_options'
13
14
  require_relative 'yard-sequel/ast_node_hash'
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YardSequel
4
+ # Holds the options of an association macro call and makes them easily
5
+ # accessible.
6
+ # @author Kai Moschcau
7
+ class AssociationOptions
8
+ # @param [Hash<Yard::Parser::Ruby::AstNode>] ast_node_hash A Hash created
9
+ # with the {AstNodeHash} module, to get the options from.
10
+ def initialize(ast_node_hash)
11
+ @ast_node_hash = {}
12
+ ast_node_hash.each do |name, parameter|
13
+ @ast_node_hash[parse_symbol_node name] = parse_symbol_node parameter
14
+ end
15
+ end
16
+
17
+ # @param [Symbol] option_name The name of the option, to get the parameter
18
+ # of.
19
+ # @return [Yard::Parser::Ruby::AstNode] the option parameter value.
20
+ def [](option_name)
21
+ @ast_node_hash[option_name]
22
+ end
23
+
24
+ private
25
+
26
+ # Extracts the String content of a Symbol literal AstNode as a Symbol. It
27
+ # gets the source, then removes the leading or trailing colon. Afterwards it
28
+ # removes the leading and trailing quotes, if there are any and returns the
29
+ # result as a Symbol.
30
+ # @param [Yard::Parser::Ruby::AstNode] ast_node The Symbol literal AstNode
31
+ # to get the content from.
32
+ # @return [Symbol] the Symbol literal's content as a Symbol.
33
+ def extract_symbol_content(ast_node)
34
+ ast_node.source.gsub(/(?:^:|:$)/, '').gsub(/(?:^['"]|['"]$)/, '').to_sym
35
+ end
36
+
37
+ # Parses a Symbol literal AstNode, if possible. This will return a Symbol
38
+ # with the Symbol literal's content String, if the literal is a Hash label,
39
+ # a normal Symbol literal or a dynamic Symbol literal without interpolation.
40
+ # @param [Yard::Parser::Ruby::AstNode] symbol_node The AstNode to get the
41
+ # content String from.
42
+ # @return [Symbol] the parsed Symbol.
43
+ # @return [Yard::Parser::Ruby::AstNode] the passed node, if it could not be
44
+ # parsed.
45
+ def parse_symbol_node(symbol_node)
46
+ if %i[symbol_literal label dyna_symbol].include? symbol_node.type
47
+ # Return if the literal contains interpolation
48
+ return symbol_node if symbol_node.jump(:string_embexpr) != symbol_node
49
+
50
+ return extract_symbol_content(symbol_node)
51
+ end
52
+
53
+ symbol_node
54
+ end
55
+ end
56
+ end
@@ -7,13 +7,14 @@ module YardSequel
7
7
  class AssociationHandler < YARD::Handlers::Ruby::DSLHandler
8
8
  def process
9
9
  log.debug { "#{self.class.name}#process call" }
10
+ @association_options = association_options
10
11
  end
11
12
 
12
13
  protected
13
14
 
14
15
  # Adds a parameter tag to a method object.
15
- # @param [YARD::CodeObjects::MethodObject] method
16
- # The method to add the parameter tag to.
16
+ # @param [YARD::CodeObjects::MethodObject] method The method to add the
17
+ # parameter tag to.
17
18
  # @param [String] name The name of the parameter.
18
19
  # @param [String] class_name The class name of the parameter.
19
20
  # @param [String] description The description of the parameter.
@@ -25,15 +26,46 @@ module YardSequel
25
26
  )
26
27
  end
27
28
 
29
+ # @return [String] the association Class without namespace.
30
+ def association_class
31
+ class_param = @association_options&.[](:class)
32
+ return class_param.to_s.split('::').last if
33
+ [String, Symbol].include? class_param.class
34
+
35
+ association_name.classify
36
+ end
37
+
38
+ # @return [String] the namespace of the association class.
39
+ def association_class_namespace
40
+ class_namespace_param = @association_options&.[](:class_namespace)
41
+ return class_namespace_param.to_s if
42
+ [String, Symbol].include? class_namespace_param.class
43
+
44
+ class_param = @association_options&.[](:class)
45
+ return class_param.to_s.rpartition('::').first if
46
+ [String, Symbol].include? class_param.class
47
+ end
48
+
49
+ # @return [String] the association Class with namespace.
50
+ def association_full_class
51
+ [association_class_namespace, association_class].compact.join('::')
52
+ end
53
+
28
54
  # @return [String] the name of the association
29
55
  def association_name
30
56
  @statement.parameters.first.jump(:ident).source
31
57
  end
32
58
 
33
- # @return [Array<YARD::Parser::Ruby::AstNode>] the association nodes
34
- # of the options Hash.
59
+ # @return [nil] If the association does not have an options parameter or
60
+ # it is empty.
61
+ # @return [AssociationOptions] the AssociationOptions of the association.
35
62
  def association_options
36
- @statement.parameters[1].filter { |node| node.type == :assoc }
63
+ option_param = @statement.parameters[1] || return
64
+ AssociationOptions.new AstNodeHash.from_ast(option_param)
65
+ rescue ArgumentError, TypeError => error
66
+ log.warn 'Could not parse association options due to syntax error.'
67
+ log.debug error.message
68
+ nil
37
69
  end
38
70
 
39
71
  # @param [String] name The name of the method object.
@@ -9,11 +9,15 @@ module YardSequel
9
9
  include YardSequel::Associations::ToOneMethods
10
10
  handles method_call(:many_to_one)
11
11
  namespace_only
12
+
12
13
  def process
13
14
  super
15
+ original_group = extra_state.group
16
+ extra_state.group = "Many to one #{association_name} association"
14
17
  create_to_one_getter
15
18
  create_to_one_setter
16
19
  create_dataset_method
20
+ extra_state.group = original_group
17
21
  end
18
22
  end
19
23
  end
@@ -9,8 +9,7 @@ module YardSequel
9
9
  # object.
10
10
  def create_dataset_method
11
11
  method = create_method_object("#{association_name}_dataset")
12
- return_tag(method, 'Sequel::Dataset', 'the association\'s'\
13
- 'dataset.')
12
+ return_tag(method, 'Sequel::Dataset', 'the association\'s dataset.')
14
13
  method
15
14
  end
16
15
  end
@@ -10,12 +10,12 @@ module YardSequel
10
10
  def create_to_many_adder
11
11
  name = association_name
12
12
  method = create_method_object "add_#{name.singularize}"
13
- method.docstring += "Associates the passed #{name.classify} "\
13
+ method.docstring += "Associates the passed #{association_class} "\
14
14
  'with `self`.'
15
- add_param_tag(method, name.singularize, name.classify,
16
- "The #{name.classify} to associate with `self`.")
17
- return_tag(method, name.classify,
18
- "the associated #{name.classify}.")
15
+ add_param_tag(method, name.singularize, association_full_class,
16
+ "The #{association_class} to associate with `self`.")
17
+ return_tag(method, association_full_class,
18
+ "the associated #{association_class}.")
19
19
  method
20
20
  end
21
21
 
@@ -25,7 +25,7 @@ module YardSequel
25
25
  name = association_name
26
26
  method = create_method_object "remove_all_#{name}"
27
27
  method.docstring += 'Removes the association of all '\
28
- "#{name.classify.pluralize} with `self`."
28
+ "#{association_class.pluralize} with `self`."
29
29
  void_return_tag method
30
30
  method
31
31
  end
@@ -35,8 +35,8 @@ module YardSequel
35
35
  def create_to_many_getter
36
36
  name = association_name
37
37
  method = create_method_object name
38
- return_tag(method, "Array<#{name.classify}>",
39
- "the associated #{name.classify.pluralize}.")
38
+ return_tag(method, "Array<#{association_full_class}>",
39
+ "the associated #{association_class.pluralize}.")
40
40
  method
41
41
  end
42
42
 
@@ -46,9 +46,9 @@ module YardSequel
46
46
  name = association_name
47
47
  method = create_method_object "remove_#{name.singularize}"
48
48
  method.docstring += 'Removes the association of the passed '\
49
- "#{name.classify} with `self`."
50
- add_param_tag(method, name.singularize, name.classify,
51
- "The #{name.classify} to remove the association "\
49
+ "#{association_class} with `self`."
50
+ add_param_tag(method, name.singularize, association_full_class,
51
+ "The #{association_class} to remove the association "\
52
52
  'with `self` from.')
53
53
  void_return_tag method
54
54
  method
@@ -10,8 +10,8 @@ module YardSequel
10
10
  def create_to_one_getter
11
11
  name = association_name
12
12
  method = create_method_object name
13
- return_tag(method, name.classify,
14
- "the associated #{name.classify}.")
13
+ return_tag(method, association_full_class,
14
+ "the associated #{association_class}.")
15
15
  method
16
16
  end
17
17
 
@@ -20,12 +20,12 @@ module YardSequel
20
20
  def create_to_one_setter
21
21
  name = association_name
22
22
  method = create_method_object "#{name}="
23
- method.docstring += "Associates the passed #{name.classify} "\
23
+ method.docstring += "Associates the passed #{association_class} "\
24
24
  'with `self`.'
25
- add_param_tag(method, name, name.classify,
26
- "The #{name.classify} to associate with `self`.")
27
- return_tag(method, name.classify,
28
- "the associated #{name.classify}.")
25
+ add_param_tag(method, name, association_full_class,
26
+ "The #{association_class} to associate with `self`.")
27
+ return_tag(method, association_full_class,
28
+ "the associated #{association_class}.")
29
29
  method
30
30
  end
31
31
  end
@@ -9,13 +9,17 @@ module YardSequel
9
9
  include YardSequel::Associations::ToManyMethods
10
10
  handles method_call(:one_to_many)
11
11
  namespace_only
12
+
12
13
  def process
13
14
  super
15
+ original_group = extra_state.group
16
+ extra_state.group = "One to many #{association_name} association"
14
17
  create_to_many_adder
15
18
  create_to_many_clearer
16
19
  create_to_many_getter
17
20
  create_to_many_remover
18
21
  create_dataset_method
22
+ extra_state.group = original_group
19
23
  end
20
24
  end
21
25
  end
@@ -1,16 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module YardSequel
4
- # Offers methods to convert an Abstract Syntax Tree to a Hash consisting
5
- # of `YARD::Parser::Ruby::AstNode`s.
4
+ # Offers methods to convert an Abstract Syntax Tree of a Hash literal or named
5
+ # method parameters to a Hash consisting of `YARD::Parser::Ruby::AstNode`s.
6
6
  # @author Kai Moschcau
7
7
  module AstNodeHash
8
8
  class << self
9
+ # Creates a new Hash from the passed AstNode. This is the main method to
10
+ # use, to create a new Hash.
11
+ # @param (see .node_hash_from_node)
12
+ # @raise (see .check_ast)
13
+ # @return (see .node_hash_from_node)
9
14
  def from_ast(ast)
10
15
  check_ast ast
11
16
  node_hash_from_node ast
12
17
  end
13
18
 
19
+ # Checks the passed AstNode for validity. If the AstNode is valid, this
20
+ # method does not raise an error.
21
+ # @raise [TypeError, ArgumentError] If the AstNode is not valid.
22
+ # @param [YARD::Parser::Ruby::AstNode] ast The AstNode to check for
23
+ # validity.
14
24
  def check_ast(ast)
15
25
  check_is_ast_node ast
16
26
  check_is_hash_or_list ast
@@ -22,12 +32,19 @@ module YardSequel
22
32
 
23
33
  private
24
34
 
35
+ # Checks if the given child AstNode has exactly two children.
36
+ # @raise [ArgumentError] If if does not have 2 children.
37
+ # @return [void]
25
38
  def check_assoc_child_has_two_children(child_ast)
26
39
  return if child_ast.children.size == 2
27
40
 
28
41
  raise(ArgumentError, 'each `:assoc` child must have two children')
29
42
  end
30
43
 
44
+ # Checks the children of the given AstNode. Mainly it first checks, if the
45
+ # AstNode has only `:assoc` type children and if each child has two
46
+ # further children.
47
+ # @return [void]
31
48
  def check_children(ast)
32
49
  check_has_only_assoc_children ast
33
50
  ast.children.each do |child_ast|
@@ -35,6 +52,9 @@ module YardSequel
35
52
  end
36
53
  end
37
54
 
55
+ # Checks if the children of the passed AstNode are all of type `:assoc`.
56
+ # @raise [ArgumentError] If there is at least one not of type `:assoc`.
57
+ # @return [void]
38
58
  def check_has_only_assoc_children(ast)
39
59
  return unless ast.children.any? { |child| child.type != :assoc }
40
60
 
@@ -42,12 +62,18 @@ module YardSequel
42
62
  'all children of the passed `ast` have to have the type `:assoc`')
43
63
  end
44
64
 
65
+ # Checks the children of a `:hash` type AstNode. If the AstNode has no
66
+ # children, this does nothing. Otherwise it runs {.check_children}.
67
+ # @return [void]
45
68
  def check_hash_children(ast)
46
69
  return if ast.children.empty?
47
70
 
48
71
  check_children ast
49
72
  end
50
73
 
74
+ # Checks, whether the passed Object is a `YARD::Parser::Ruby::AstNode`.
75
+ # @raise [TypeError] If the passed Object is not of the correct type.
76
+ # @return [void]
51
77
  def check_is_ast_node(ast)
52
78
  return if ast.is_a? YARD::Parser::Ruby::AstNode
53
79
 
@@ -55,6 +81,9 @@ module YardSequel
55
81
  'the passed `ast` has to be a `YARD::Parser::Ruby::AstNode`')
56
82
  end
57
83
 
84
+ # Checks, whether the passed AstNode is of Type `:hash` or `:list`.
85
+ # @raise [ArgumentError] If the passed AstNode is not of the correct type.
86
+ # @return [void]
58
87
  def check_is_hash_or_list(ast)
59
88
  return if %i[hash list].include? ast.type
60
89
 
@@ -62,6 +91,10 @@ module YardSequel
62
91
  "the passed `ast`'s type has to be `:hash` or `:list`")
63
92
  end
64
93
 
94
+ # Checks the children of a `:list` type AstNode. If the AstNode has no
95
+ # children, this raises an error. Otherwise it runs {.check_children}.
96
+ # @raise [ArgumentError] If the passed AstNode has no children.
97
+ # @return [void]
65
98
  def check_list_children(ast)
66
99
  if ast.children.empty?
67
100
  raise(ArgumentError,
@@ -70,6 +103,10 @@ module YardSequel
70
103
  check_children ast
71
104
  end
72
105
 
106
+ # Converts the passed AstNode to a Hash.
107
+ # @param [YARD::Parser::Ruby::AstNode] ast The AstNode to convert to a
108
+ # Hash.
109
+ # @return [Hash<YARD::Parser::Ruby::AstNode>] the converted Hash.
73
110
  def node_hash_from_node(ast)
74
111
  hash = {}
75
112
  ast.children.each { |cn| hash[cn.children[0]] = cn.children[1] }
@@ -7,11 +7,11 @@ module YardSequel
7
7
 
8
8
  # The minor version number.
9
9
  # Used for changes that are backwards compatible.
10
- V_MINOR = 1
10
+ V_MINOR = 2
11
11
 
12
12
  # The build version number.
13
13
  # Used for internal changes.
14
- V_BUILD = 1
14
+ V_BUILD = 0
15
15
 
16
16
  # The version of the Sequel models.
17
17
  VERSION = Gem::Version.new("#{V_MAJOR}.#{V_MINOR}.#{V_BUILD}")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yard-sequel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kai Moschcau
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-12-04 00:00:00.000000000 Z
11
+ date: 2018-12-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: coveralls
@@ -122,6 +122,7 @@ extra_rdoc_files: []
122
122
  files:
123
123
  - ".yardopts"
124
124
  - lib/yard-sequel.rb
125
+ - lib/yard-sequel/association_options.rb
125
126
  - lib/yard-sequel/associations.rb
126
127
  - lib/yard-sequel/associations/association_handler.rb
127
128
  - lib/yard-sequel/associations/many_to_one_handler.rb