acls 1.1.3 → 2.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7b1e9054c2aa8a265732a826ab96128fe5101388
4
- data.tar.gz: 51daeadc17700f03440fcdc417f56d90ab365897
3
+ metadata.gz: dbea83036ba56155987eaa3cdfa0955c95fd0410
4
+ data.tar.gz: cbe8a2759eebbbbd26be047e5c9bc5639f4539a3
5
5
  SHA512:
6
- metadata.gz: bb760e38f2fab04f17a321c45439afefa8acf641c0f25888d8019e153e7ae277cd4bcc39d196c89a9ad12092127da22079b477debc41b1aa5f7a41e7f84bbcf1
7
- data.tar.gz: 3f1d7c3c865a8161817e55855e76c50b03dd2f9933b7b9fa3f7c5c41106073582613565c69d848201dcead4ccfa3e2d0f7b11ebe2f68e8e2017a74a5c314754c
6
+ metadata.gz: 950a74f0011826e6447cc715dbead105c5817e19759eb00586a8f1a7f292d2b55bfe4ddfdab6c318ae9579813b7e8967b1756bc36481613a02788235c956cb69
7
+ data.tar.gz: 51905b9dbfcf6c444310a4d393f03da42842f6d0a48bbdd21a853228730f3f9a0d77d818217dd3403ebf00701d659751b3d138a20ef90d1f659beceda2324852
@@ -1,4 +1,5 @@
1
1
  require 'active_support/inflector'
2
+ require 'parser/current'
2
3
 
3
4
  module ACLS
4
5
  require_relative './acls/loader'
@@ -14,49 +14,43 @@ module ACLS
14
14
  private
15
15
 
16
16
  def build_trees(paths, opts)
17
- if paths.respond_to?(:each)
18
- paths.map { |path| build_tree(path, opts) }
19
- else
20
- [build_tree(paths, opts)]
21
- end
22
- end
23
-
24
- def build_tree(path, opts)
25
- Parser.parse(path)
17
+ paths = [paths] unless paths.respond_to?(:map)
18
+ paths.map { |path| Parser.parse(path) }
26
19
  end
27
20
 
28
21
  def autoload_statement(tree)
29
22
  "autoload :#{tree.name}, \"#{tree.source}\""
30
23
  end
31
24
 
32
- def autoload_root(tree, opts)
33
- root = Object
34
- if opts[:root_ns].is_a?(TrueClass)
35
- root = submodule(root, File.basename(tree.directory).camelize)
36
- elsif opts[:root_ns].is_a?(String)
37
- opts[:root_ns].split('::').each { |ns| root = submodule(root, ns) }
25
+ def autoload_tree(mod, tree, opts)
26
+ unless exclude?(tree, opts)
27
+ if tree.children.empty?
28
+ mod.module_eval(autoload_statement(tree))
29
+ else
30
+ mod = submodule(mod, tree.name)
31
+ end
32
+ tree.children.map { |child| autoload_tree(mod, child, opts) }
38
33
  end
39
- root
40
34
  end
41
35
 
42
36
  def autoload_trees(trees, opts)
43
37
  trees.map do |tree|
44
- root = autoload_root(tree, opts)
38
+ root = Object
45
39
  tree.children.map do |node|
46
40
  autoload_tree(root, node, opts)
47
41
  end
48
42
  end
49
43
  end
50
44
 
51
- def autoload_tree(mod, tree, opts)
52
- unless exclude?(mod, tree, opts)
53
- if tree.source
54
- mod.module_eval(autoload_statement(tree))
45
+ def exclude?(tree, opts)
46
+ opts[:exclude].each do |pattern|
47
+ if pattern.is_a?(String)
48
+ return true if pattern == File.basename(tree.path, ".rb")
55
49
  else
56
- sub = submodule(mod, tree.name)
57
- tree.children.map { |child| autoload_tree(sub, child, opts) }
50
+ return true if pattern.match(tree.path)
58
51
  end
59
52
  end
53
+ false
60
54
  end
61
55
 
62
56
  def submodule(parent, child)
@@ -65,17 +59,6 @@ module ACLS
65
59
  parent.const_set(child, Module.new)
66
60
  end
67
61
 
68
- def exclude?(mod, tree, opts)
69
- opts[:exclude].each do |pattern|
70
- if pattern.is_a?(String)
71
- return true if pattern == File.basename(tree.path, ".rb")
72
- else
73
- return true if pattern.match(tree.path)
74
- end
75
- end
76
- false
77
- end
78
-
79
62
  end
80
63
  end
81
64
  end
@@ -2,58 +2,77 @@ module ACLS
2
2
  class Parser
3
3
  class << self
4
4
 
5
- def parse(base_dir, namespace=nil)
6
- parse_tree(Tree.new(nil, namespace, base_dir))
5
+ # Given a base directory, parse all Ruby source files into a custom Tree
6
+ # representation.
7
+ def parse(base_dir)
8
+ parse_tree(Tree.new(nil, nil, base_dir), base_dir)
7
9
  end
8
10
 
9
11
  private
10
12
 
11
- def parse_tree(parent)
12
- Dir.entries(parent.directory).each do |entry|
13
- next if entry[0] == '.'
14
- full_path = "#{parent.directory}/#{entry}"
15
- name = entry.sub(".rb", "").strip.camelize
16
- if File.directory?(full_path)
17
- child = parent.make_child(name, full_path)
18
- parse_tree(child)
19
- else
20
- class_name = guess_classname(name, full_path)
21
- parent.make_child(class_name, parent.directory, full_path)
22
- end
23
- end
24
- parent
13
+ # Attempt to parse a collection of module/class names to determine a
14
+ # fully-qualified namespace for a source module/class.
15
+ def parse_names(node, parent, source)
16
+ return parent if node.nil?
17
+
18
+ parent = parse_names(node.children.first, parent, source)
19
+ parent.make_child(node.children.last, '', source)
20
+ end
21
+
22
+ # Parse an AST to get the top-most parent name and build a module/class
23
+ # chain from there.
24
+ def parse_parent(ast, parent, source)
25
+ name = ast.children.first
26
+ parse_names(name, parent, source)
25
27
  end
26
28
 
27
- def guess_classname(name, file)
28
- process_classname_matches( scan_classnames(file), name )
29
+ # Parse a module. Similar to parsing a class, except you continue to parse
30
+ # child nodes.
31
+ def parse_module(ast, parent, source)
32
+ parent = parse_parent(ast, parent, source)
33
+ ast.children[1..-1].map { |node| parse_ast(node, parent, source) }
29
34
  end
30
35
 
31
- def scan_classnames(file)
32
- contents = File.read(file)
33
- contents.scrub! if (contents.respond_to?(:scrub!))
34
- contents.scan(/(class|module)\s+([^\n\r<]+)/)
36
+ # Parse a class. Similar to parsing a module, except you do not parse any
37
+ # child nodes.
38
+ def parse_class(ast, parent, source)
39
+ parse_parent(ast, parent, source)
35
40
  end
36
41
 
37
- def process_classname_matches(matches, name)
38
- if match = best_classname_match(matches, name)
39
- base_classname(match[1])
42
+ # Parse an AST Node.
43
+ def parse_ast(ast, parent, source)
44
+ return if ast.nil? || !ast.is_a?(::AST::Node)
45
+
46
+ if ast.type == :module
47
+ parse_module(ast, parent, source)
48
+ elsif ast.type == :class
49
+ parse_class(ast, parent, source)
40
50
  else
41
- name
51
+ ast.children.each { |node| parse_ast(node, parent, source) }
42
52
  end
43
- end
44
53
 
45
- def best_classname_match(matches, name)
46
- return nil unless matches
47
- matches.drop_while { |match| !match_classname(match[1], name) }.first
54
+ parent
48
55
  end
49
56
 
50
- def match_classname(match, name)
51
- base_classname(match).downcase == name.downcase
57
+ # Convert a source file into an AST and parse it.
58
+ def parse_file(tree, file)
59
+ ast = ::Parser::CurrentRuby.parse(File.read(file))
60
+ parse_ast(ast, tree, file)
52
61
  end
53
62
 
54
- def base_classname(name)
55
- name.split("::").last.strip
63
+ def parse_tree(tree, directory)
64
+ Dir.entries(directory).each do |entry|
65
+ next if entry[0] == '.'
66
+ full_path = "#{directory}/#{entry}"
67
+ if File.directory?(full_path)
68
+ parse_tree(tree, full_path)
69
+ elsif entry.end_with?('.rb')
70
+ parse_file(tree, full_path)
71
+ end
72
+ end
73
+ tree
56
74
  end
75
+
57
76
  end
58
77
  end
59
78
  end
@@ -16,12 +16,29 @@ module ACLS
16
16
  child
17
17
  end
18
18
 
19
+ # If a source file is specified, returns the path to the source file.
19
20
  def path
20
21
  @source || @directory
21
22
  end
22
23
 
23
- def to_s
24
- "name: #{@name}, source: #{@source}, directory: #{@directory}, parent: #{@parent}, children: #{@children.length}"
24
+ # Find the first child with a given name, including the calling node in the
25
+ # search.
26
+ def find(name)
27
+ return self if @name == name
28
+ @children.find { |child| child.find(name) }
29
+ end
30
+
31
+ def to_s(level=0)
32
+ tab = '**' * 2 * level
33
+ <<EOS
34
+ #{tab} level: #{level}
35
+ #{tab} name: #{@name}
36
+ #{tab} source: #{@source}
37
+ #{tab} directory: #{@directory}
38
+ #{tab} children => [
39
+ #{@children.map { |child| child.to_s(level+1) }.join}
40
+ #{tab} ]
41
+ EOS
25
42
  end
26
43
 
27
44
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acls
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.3
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kolo Rahl
@@ -30,6 +30,26 @@ dependencies:
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
32
  version: 4.2.5
33
+ - !ruby/object:Gem::Dependency
34
+ name: parser
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '2.3'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 2.3.0
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '2.3'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 2.3.0
33
53
  - !ruby/object:Gem::Dependency
34
54
  name: rspec
35
55
  requirement: !ruby/object:Gem::Requirement