cocoadex 1.4 → 1.5

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 (44) hide show
  1. data/bin/cdex_completion +7 -0
  2. data/bin/cocoadex +5 -3
  3. data/changelog.md +5 -0
  4. data/lib/cocoadex/docset_helper.rb +8 -4
  5. data/lib/cocoadex/extensions.rb +4 -0
  6. data/lib/cocoadex/keyword.rb +30 -103
  7. data/lib/cocoadex/model.rb +56 -0
  8. data/lib/cocoadex/models/callback.rb +12 -0
  9. data/lib/cocoadex/models/class.rb +2 -2
  10. data/lib/cocoadex/models/constant.rb +41 -0
  11. data/lib/cocoadex/models/data_type.rb +47 -0
  12. data/lib/cocoadex/models/element.rb +14 -1
  13. data/lib/cocoadex/models/entity.rb +6 -0
  14. data/lib/cocoadex/models/function.rb +28 -0
  15. data/lib/cocoadex/models/generic_ref.rb +88 -0
  16. data/lib/cocoadex/models/method.rb +21 -70
  17. data/lib/cocoadex/models/nested_node_element.rb +17 -0
  18. data/lib/cocoadex/models/parameter.rb +20 -0
  19. data/lib/cocoadex/models/property.rb +3 -18
  20. data/lib/cocoadex/models/result_code.rb +17 -0
  21. data/lib/cocoadex/models/seq_node_element.rb +53 -0
  22. data/lib/cocoadex/parser.rb +22 -18
  23. data/lib/cocoadex/serializer.rb +18 -8
  24. data/lib/cocoadex/tokenizer.rb +123 -0
  25. data/lib/cocoadex/tools/completion_helper.rb +84 -0
  26. data/lib/cocoadex/version.rb +1 -1
  27. data/lib/cocoadex.rb +12 -10
  28. data/lib/ext/nil.rb +3 -0
  29. data/lib/ext/string.rb +9 -0
  30. data/lib/ext/template_helpers.rb +20 -0
  31. data/lib/ext/xml_element.rb +10 -0
  32. data/readme.md +36 -8
  33. data/views/class.erb +35 -0
  34. data/views/constant.erb +10 -0
  35. data/views/constant_group.erb +28 -0
  36. data/views/data_type.erb +47 -0
  37. data/views/generic_ref.erb +28 -0
  38. data/views/method.erb +34 -0
  39. data/views/multiple.erb +4 -0
  40. data/views/property.erb +14 -0
  41. data/views/result_code.erb +7 -0
  42. metadata +50 -10
  43. data/bin/cocoadex_completion.sh +0 -36
  44. data/lib/cocoadex/templates.rb +0 -114
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # Function to print all keyword tags by scope
3
+ # (Helper for zsh completion)
4
+
5
+ require 'cocoadex'
6
+
7
+ puts Cocoadex::CompletionHelper.new(ARGV[0]).scope_matches.join("\n")
data/bin/cocoadex CHANGED
@@ -18,15 +18,15 @@ main do |query|
18
18
  end
19
19
  if options[:configure]
20
20
  DocSetHelper.search_and_index
21
+ elsif options[:'generate-tags']
22
+ CompletionHelper.generate_tags!
21
23
  elsif options[:'load-docset']
22
24
  paths = options[:'load-docset'].map do |p|
23
25
  File.expand_path(p)
24
26
  end.uniq
25
27
  DocSetHelper.search_and_index(paths)
26
28
  elsif query
27
- if Keyword.loaded?
28
- logger.debug "Loading index..."
29
- Keyword.read
29
+ if Tokenizer.loaded?
30
30
  Cocoadex.search(query, options[:first])
31
31
  else
32
32
  puts "No DocSets loaded. Run `cocodex --configure` to search for existing DocSets."
@@ -43,6 +43,8 @@ arg :query, :optional
43
43
 
44
44
  on("--verbose","Be verbose")
45
45
 
46
+ on("--generate-tags","Generate a tags file from indexed docsets and exit")
47
+
46
48
  on("--configure","Index all DocSets in default locations")
47
49
 
48
50
  on("--first","Load first result when multiple matches exist")
data/changelog.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.5
4
+
5
+ - Searching for constants, functions, data types, callbacks, and result codes are now supported!
6
+ - Added smart completion; `Class-method`, `Class+method`, and `Class.property` can now be tab-completed
7
+
3
8
  ## 1.4
4
9
 
5
10
  - Fixed parsing error on non-ASCII characters. Patch submitted by farcaller.
@@ -1,5 +1,7 @@
1
1
 
2
2
  module Cocoadex
3
+
4
+ # Helper for finding and indexing DocSets
3
5
  class DocSetHelper
4
6
 
5
7
  ROOT_PATHS = [
@@ -15,7 +17,9 @@ module Cocoadex
15
17
 
16
18
  def self.docset_paths
17
19
  @paths ||= begin
18
- ROOT_PATHS.map { |path| Dir.glob(File.expand_path(path)+'/*/') }.flatten
20
+ ROOT_PATHS.map do |path|
21
+ Dir.glob(File.expand_path(path)+'/*/')
22
+ end.flatten
19
23
  end
20
24
  end
21
25
 
@@ -28,8 +32,8 @@ module Cocoadex
28
32
  end
29
33
 
30
34
  if docsets.size > 0
31
- Keyword.write(:overwrite)
32
- Keyword.generate_tags!
35
+ Tokenizer.persist
36
+ CompletionHelper.generate_tags!
33
37
  write(docsets)
34
38
  end
35
39
  logger.info "Done! #{docsets.size} DocSet#{docsets.size == 1 ? '':'s'} indexed."
@@ -45,7 +49,7 @@ module Cocoadex
45
49
 
46
50
  def self.write docsets
47
51
  @docsets = docsets
48
- Serializer.write(data_path, docsets, :overwrite)
52
+ Serializer.write_array(data_path, docsets, :overwrite)
49
53
  end
50
54
  end
51
55
  end
@@ -0,0 +1,4 @@
1
+ require '../ext/nil'
2
+ require '../ext/string'
3
+ require '../ext/xml_element'
4
+ require '../ext/template_helpers'
@@ -11,41 +11,45 @@ module Cocoadex
11
11
  CLASS_PROP_DELIM = '.'
12
12
  SCOPE_CHARS = [CLASS_PROP_DELIM,CLASS_METHOD_DELIM,INST_METHOD_DELIM]
13
13
 
14
- def self.datastore
15
- @store ||= []
14
+ # Search the cache for matching text
15
+ def self.find text
16
+ logger.debug "Searching tokens for #{text}"
17
+ if scope = Keyword.get_scope(text)
18
+ class_name, term = text.split(scope)
19
+ find_with_scope(scope, class_name, term)
20
+ else
21
+ keys = Tokenizer.fuzzy_match(text)
22
+ keys.map {|k| k.to_element }
23
+ end
16
24
  end
17
25
 
18
- # Cache storage location
19
- def self.data_path
20
- Cocoadex.config_file("data/store.blob")
26
+ def self.get_scope text
27
+ SCOPE_CHARS.detect {|c| text.include? c}
21
28
  end
22
29
 
23
- def self.tags_path
24
- Cocoadex.config_file("tags")
30
+ def initialize term, type, docset, url
31
+ @term, @type, @docset, @url = term, type, docset, url
25
32
  end
26
33
 
27
- # Search the cache for matching text
28
- def self.find text
29
- if scope = SCOPE_CHARS.detect {|c| text.include? c }
30
- class_name, term = text.split(scope)
31
- logger.debug "Searching scope: #{scope}, #{class_name}, #{term}"
32
- find_with_scope scope, class_name, term
33
- else
34
- logger.debug "Searching Keyword datastore (#{datastore.size}): #{text}"
35
- keys = datastore.select {|k| k.term.start_with? text }
36
- logger.debug "#{keys.size} keys found"
37
- if key = keys.detect {|k| k.term == text }
38
- keys = [key]
39
- logger.debug "Exact match!"
40
- end
41
- untokenize(keys)
42
- end
34
+ def to_element
35
+ Tokenizer.untokenize([self]).first
43
36
  end
44
37
 
38
+ def inspect
39
+ "<Keyword:#{type} @term=\"#{term}\">"
40
+ end
41
+
42
+ def to_s
43
+ "#{type} => #{term}"
44
+ end
45
+
46
+ private
47
+
45
48
  # Find matches for term within a given class
46
49
  def self.find_with_scope scope, class_name, term
47
- if class_key = datastore.detect {|k| k.term == class_name }
48
- klass = untokenize([class_key]).first
50
+ if class_key = Tokenizer.match(class_name)
51
+ return [] unless class_key.type == :class
52
+ klass = class_key.to_element
49
53
  list = case scope
50
54
  when CLASS_PROP_DELIM
51
55
  klass.methods + klass.properties
@@ -59,82 +63,5 @@ module Cocoadex
59
63
  []
60
64
  end
61
65
  end
62
-
63
- # Are any docsets loaded into the cache?
64
- def self.loaded?
65
- File.exists? data_path
66
- end
67
-
68
- # Read a serialized cache file into an Array
69
- def self.read
70
- @store = Serializer.read(data_path)
71
- logger.debug "Loaded #{datastore.size} tokens"
72
- end
73
-
74
- # Write a cache Array as a serialized file
75
- def self.write style
76
- Serializer.write(data_path, datastore, style)
77
- end
78
-
79
- def self.tags
80
- @tags ||= begin
81
- if File.exists? tags_path
82
- IO.read(tags_path).split('\n')
83
- else
84
- []
85
- end
86
- end
87
- end
88
-
89
- # Build a tags file from existing kewords
90
- def self.generate_tags!
91
- text = datastore.map {|k| k.term }.join('\n')
92
- Serializer.write_text tags_path, text
93
- end
94
-
95
- # Create Cocoadex model objects for Keyword references
96
- def self.untokenize keys
97
- keys.map do |key|
98
- case key.type
99
- when :class
100
- Cocoadex::Class.new(key.url)
101
- when :method, :property
102
- if class_key = datastore.detect {|k| k.id == key.fk}
103
- klass = Cocoadex::Class.new(class_key.url)
104
- logger.debug "Searching #{key.type} list of #{klass.name}"
105
- list = key.type == :method ? klass.methods : klass.properties
106
- list.detect {|m| m.name == key.term}
107
- end
108
- end
109
- end
110
- end
111
-
112
- # Find all searchable keywords in a class and add to cache
113
- def self.tokenize_class docset, path, id
114
- klass = Cocoadex::Class.new(path)
115
- class_key = Keyword.new(klass.name, :class, docset, path)
116
- class_key.id = id
117
- datastore << class_key
118
-
119
- {:method => klass.methods, :property => klass.properties}.each do |type,list|
120
- list.each do |item|
121
- item_key = Keyword.new(item.name, type, docset, path)
122
- item_key.fk = id
123
- datastore << item_key
124
- end
125
- end
126
- end
127
-
128
- def initialize term, type, docset, url
129
- @term, @type, @docset, @url = term, type, docset, url
130
- end
131
-
132
- def inspect
133
- "<Keyword#{type} @term=#{term}>"
134
- end
135
-
136
- def to_s
137
- "#{type} => #{term}"
138
- end
139
66
  end
140
- end
67
+ end
@@ -0,0 +1,56 @@
1
+ require 'cocoadex/models/docset'
2
+ require 'cocoadex/models/element'
3
+ require 'cocoadex/models/seq_node_element'
4
+ require 'cocoadex/models/nested_node_element'
5
+ require 'cocoadex/models/entity'
6
+ require 'cocoadex/models/constant'
7
+ require 'cocoadex/models/parameter'
8
+ require 'cocoadex/models/function'
9
+ require 'cocoadex/models/callback'
10
+ require 'cocoadex/models/result_code'
11
+ require 'cocoadex/models/data_type'
12
+ require 'cocoadex/models/generic_ref'
13
+ require 'cocoadex/models/method'
14
+ require 'cocoadex/models/property'
15
+ require 'cocoadex/models/class'
16
+
17
+ # Class Structure -------------
18
+ #
19
+ # DocSet
20
+ # Element
21
+ # Entity
22
+ # Class
23
+ # GenericRef
24
+ # NestedNodeElement
25
+ # Method
26
+ # Property
27
+ # SequentialNodeElement
28
+ # Callback
29
+ # ConstantGroup
30
+ # DataType
31
+ # Function
32
+ # Constant
33
+ # Parameter
34
+ # ResultCode
35
+ #
36
+ # Relationship Tree -----------
37
+ # Class
38
+ # Method
39
+ # Parameter
40
+ # Property
41
+ #
42
+ # GenericRef
43
+ # Callback
44
+ # Parameter
45
+ # ConstantGroup
46
+ # Constant
47
+ # DataType
48
+ # Parameter
49
+ # Function
50
+ # Parameter
51
+ #
52
+ #
53
+ module Cocoadex
54
+ class Model
55
+ end
56
+ end
@@ -0,0 +1,12 @@
1
+
2
+ module Cocoadex
3
+ class Callback < Function
4
+ def type
5
+ "Callback"
6
+ end
7
+
8
+ def discussion
9
+ @discussion
10
+ end
11
+ end
12
+ end
@@ -4,7 +4,7 @@ require 'set'
4
4
  module Cocoadex
5
5
  # A model of a Cocoa API class or protocol
6
6
  class Class < Entity
7
- TEMPLATE=Cocoadex::Templates::CLASS_DESCRIPTION
7
+ TEMPLATE_NAME=:class
8
8
 
9
9
  attr_reader :description, :overview
10
10
 
@@ -48,7 +48,7 @@ module Cocoadex
48
48
  @parents = doc.css("div.zSharedSpecBoxHeadList").first.css('a').map {|node| node.text}
49
49
 
50
50
  parse_properties(doc)
51
- parse_tasks(doc)
51
+ # parse_tasks(doc)
52
52
  parse_methods(doc)
53
53
  end
54
54
 
@@ -0,0 +1,41 @@
1
+
2
+ module Cocoadex
3
+ class ConstantGroup < SequentialNodeElement
4
+ TEMPLATE_NAME=:constant_group
5
+
6
+ attr_reader :abstract, :declaration,
7
+ :discussion, :declared_in
8
+
9
+ def constants
10
+ @constants ||= []
11
+ end
12
+
13
+ def handle_node node
14
+ if node.classes.include? "termdef"
15
+ node.css("dt").each do |field_title_node|
16
+ source = "#{@origin} > #{@name}"
17
+ field_name = field_title_node.css("code").text
18
+ description = field_title_node.next.css("p").map {|p| p.text}.join("\n")
19
+ constants << Constant.new(source,field_name, description)
20
+ end
21
+ elsif node.name == "p" and node.classes.empty?
22
+ @abstract = node.text
23
+ end
24
+ end
25
+ end
26
+
27
+ class Constant < Element
28
+ TEMPLATE_NAME=:constant
29
+
30
+ attr_reader :description
31
+
32
+ def initialize origin, name, description
33
+ @origin = origin
34
+ @name, @description = name, description
35
+ end
36
+
37
+ def origin
38
+ @origin
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,47 @@
1
+
2
+ module Cocoadex
3
+
4
+ class DataType < SequentialNodeElement
5
+ TEMPLATE_NAME=:data_type
6
+
7
+ class Field < Parameter;end
8
+
9
+ attr_reader :abstract, :declaration, :declared_in,
10
+ :discussion, :availability, :considerations
11
+ attr_accessor :next_termdef
12
+
13
+ def fields
14
+ @fields ||= []
15
+ end
16
+
17
+ def constants
18
+ @constants ||= []
19
+ end
20
+
21
+ def origin
22
+ @origin
23
+ end
24
+
25
+ def handle_node node
26
+ if ["Fields","Constants"].include? node.text
27
+ next_termdef = node.text
28
+ elsif node.classes.include? "termdef" and not next_termdef.nil?
29
+ if list = termdef_to_properties(next_termdef)
30
+ node.css("dt").each do |field_title_node|
31
+ field_name = field_title_node.css("code").text
32
+ description = field_title_node.next.text
33
+ list << Field.new(field_name, description)
34
+ end
35
+ next_termdef = ""
36
+ end
37
+ end
38
+ end
39
+
40
+ def termdef_to_properties termdef
41
+ case termdef
42
+ when "Fields" then fields
43
+ when "Constants" then constants
44
+ end
45
+ end
46
+ end
47
+ end
@@ -12,7 +12,9 @@ module Cocoadex
12
12
  end
13
13
 
14
14
  def print
15
- template = self.class.const_get(:TEMPLATE)
15
+ template_name = self.class.const_get("TEMPLATE_NAME")
16
+ path = Cocoadex.view_path(template_name)
17
+ template = IO.read(path, :mode => 'rb')
16
18
  ERB.new(template, nil, '<>').result(binding)
17
19
  end
18
20
 
@@ -27,5 +29,16 @@ module Cocoadex
27
29
  def type
28
30
  raise "#{self.class}#type is not defined"
29
31
  end
32
+
33
+ def parse_parameters node
34
+ node.css("dt").each do |param|
35
+ name_nodes = param.css("em")
36
+ if name_nodes.size > 0
37
+ name = param.css("em").first.text
38
+ description = param.next.css("p").first.text
39
+ parameters << Parameter.new(name, description)
40
+ end
41
+ end
42
+ end
30
43
  end
31
44
  end
@@ -2,8 +2,10 @@ module Cocoadex
2
2
  # A top level element, roughly equivalent to one
3
3
  # page of documentation
4
4
  class Entity < Element
5
+ attr_reader :path
5
6
 
6
7
  def initialize path
8
+ @path = path
7
9
  text = clean(IO.read(path, :mode => 'rb'))
8
10
  document = Nokogiri::HTML(text)
9
11
  parse(document)
@@ -18,5 +20,9 @@ module Cocoadex
18
20
  def strip text
19
21
  text.gsub("&#xA0;&#xA0;","")
20
22
  end
23
+
24
+ def section_by_title doc, title
25
+ doc.css("section").to_a.detect {|s| s.css("h2.jump").text == title }
26
+ end
21
27
  end
22
28
  end
@@ -0,0 +1,28 @@
1
+
2
+ module Cocoadex
3
+ class Function < SequentialNodeElement
4
+ attr_reader :abstract, :declaration, :declared_in,
5
+ :availability, :return_value
6
+ TEMPLATE_NAME=:method
7
+
8
+ def parameters
9
+ @parameters ||= []
10
+ end
11
+
12
+ def discussion
13
+ ""
14
+ end
15
+
16
+ def handle_node node
17
+ if node.classes.include? "parameters"
18
+ parse_parameters(node)
19
+ else
20
+ logger.debug("Unhandled function property: #{node.classes} => #{node.text}")
21
+ end
22
+ end
23
+
24
+ def type
25
+ "Function"
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,88 @@
1
+
2
+ module Cocoadex
3
+ # A non-class reference document containing functions,
4
+ # constants, callbacks, result codes, and data types
5
+ class GenericRef < Entity
6
+ attr_reader :specs, :data_types, :overview,
7
+ :result_codes, :const_groups, :functions,
8
+ :callbacks
9
+ TEMPLATE_NAME=:generic_ref
10
+
11
+ def parse doc
12
+ @name = doc.title.sub("Reference","").strip
13
+ @specs = {}
14
+
15
+ parse_specbox(doc)
16
+ parse_overview(doc)
17
+ parse_data_types(doc)
18
+ parse_result_codes(doc)
19
+ parse_constants(doc)
20
+ parse_functions(doc)
21
+ parse_callbacks(doc)
22
+ end
23
+
24
+ def constants
25
+ @const_groups.map {|g| g.constants}.flatten
26
+ end
27
+
28
+ def parse_overview doc
29
+ if section = section_by_title(doc, "Overview")
30
+ @overview = section.text.sub("Overview","")
31
+ else
32
+ @overview = ""
33
+ end
34
+ end
35
+
36
+ def parse_specbox doc
37
+ specbox = doc.css(".specbox")
38
+ return if specbox.to_a.empty?
39
+ specbox.first.css("tr").each do |row|
40
+ title = row.css("td").first.css("strong").text
41
+ value = row.css("td").to_a[1].text.strip
42
+ @specs[title] = value
43
+ end
44
+ end
45
+
46
+ def parse_callbacks doc
47
+ @callbacks = []
48
+ parse_section(doc, @callbacks, "Callbacks", Callback)
49
+ end
50
+
51
+ def parse_functions doc
52
+ @functions = []
53
+ parse_section(doc, @functions, "Functions", Function)
54
+ end
55
+
56
+ def parse_data_types doc
57
+ @data_types = []
58
+ parse_section(doc, @data_types, "Data Types", DataType)
59
+ end
60
+
61
+ def parse_constants doc
62
+ @const_groups = []
63
+ parse_section(doc, @const_groups, "Constants",ConstantGroup)
64
+ end
65
+
66
+ def parse_section doc, list, title, klass
67
+ if section = section_by_title(doc, title)
68
+ section.css("h3").each do |type_title|
69
+ list << klass.new(@name, type_title)
70
+ end
71
+ end
72
+ end
73
+
74
+ def parse_result_codes doc
75
+ @result_codes = []
76
+ if section = section_by_title(doc, "Result Codes")
77
+ table = section.css("table").first
78
+ table.css("tr").each do |row|
79
+ if cells = row.css("td") and cells.size > 0
80
+ value = cells[1].text
81
+ description = cells[2].css("p").map {|p| p.text}.join("\n\n")
82
+ @result_codes << ResultCode.new(@name, cells.first.text, value, description)
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -1,81 +1,32 @@
1
1
 
2
2
  module Cocoadex
3
- class Class < Entity
4
- # A model of a method in a Cocoa class
5
- class Method < Element
6
- TEMPLATE=Cocoadex::Templates::METHOD_DESCRIPTION
3
+ # A model of a method in a Cocoa class
4
+ class Method < NestedNodeElement
5
+ TEMPLATE_NAME=:method
7
6
 
8
- attr_reader :abstract, :declaration, :discussion,
9
- :declared_in, :availability, :parameters,
10
- :return_value, :scope, :parent
7
+ attr_reader :abstract, :declaration, :discussion,
8
+ :declared_in, :availability, :parameters,
9
+ :return_value, :scope, :parent
11
10
 
12
- class Parameter
13
- include Comparable
14
-
15
- attr_reader :name, :description
16
-
17
- def initialize name, description
18
- @name, @description = name, description
19
- end
20
-
21
- def to_s
22
- "#{name} - #{description}"
23
- end
24
-
25
- def <=> other
26
- name <=> other.name if other.respond_to? :name
27
- end
28
- end
29
-
30
- def parameters
31
- @parameters ||= []
32
- end
33
-
34
- def initialize parent_class, type, node
35
- @parent = parent_class
36
- @scope = type
37
- @name = node.css("h3.#{type}Method").first.text
38
- logger.debug("parsing #{@type} method #{@name}")
39
-
40
- @abstract = node.css(".abstract").first.text
41
- @declaration = node.css(".declaration").first.text
42
-
43
- decl_nodes = node.css(".declaredIn code.HeaderFile")
44
- @declared_in = decl_nodes.first.text if decl_nodes.size > 0
45
-
46
- discussion_node = node.css(".discussion > p")
47
- @discussion = discussion_node.first.text if discussion_node.length > 0
48
-
49
- return_nodes = node.css(".return_value p")
50
- @return_value = return_nodes.first.text if return_nodes.size > 0
51
-
52
- ava_nodes = node.css(".availability > ul > li")
53
- @availability = ava_nodes.first.text if ava_nodes.size > 0
11
+ def parameters
12
+ @parameters ||= []
13
+ end
54
14
 
55
- parse_parameters(node)
56
- end
15
+ def initialize parent_class, type, node
16
+ @parent = parent_class
17
+ @scope = type
18
+ @name = node.css("h3.#{type}Method").first.text
57
19
 
58
- def parse_parameters node
59
- if parameters = node.css(".parameters") and parameters.length > 0
60
- @parameters = []
61
- parameters.first.css("dt").each do |param|
62
- name_nodes = param.css("em")
63
- if name_nodes.size > 0
64
- name = param.css("em").first.text
65
- description = param.next.css("p").first.text
66
- @parameters << Parameter.new(name, description)
67
- end
68
- end
69
- end
70
- end
20
+ parse_properties(node)
21
+ parse_parameters(node.css(".parameters").first)
22
+ end
71
23
 
72
- def type
73
- "#{scope.to_s.capitalize} Method"
74
- end
24
+ def type
25
+ "#{scope.to_s.capitalize} Method"
26
+ end
75
27
 
76
- def origin
77
- parent.to_s
78
- end
28
+ def origin
29
+ parent.to_s
79
30
  end
80
31
  end
81
32
  end