mudguard 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +8 -0
  3. data/.mudguard.yml +6 -0
  4. data/.rubocop.yml +2 -0
  5. data/Gemfile.lock +25 -23
  6. data/Guardfile +1 -1
  7. data/README.md +62 -9
  8. data/exe/mudguard +5 -12
  9. data/lib/mudguard.rb +2 -17
  10. data/lib/mudguard/application/application.rb +33 -0
  11. data/lib/mudguard/domain/const_visitor.rb +20 -0
  12. data/lib/mudguard/domain/consts.rb +81 -0
  13. data/lib/mudguard/domain/dependencies.rb +47 -0
  14. data/lib/mudguard/domain/dependency.rb +28 -0
  15. data/lib/mudguard/domain/dependency_visitor.rb +32 -0
  16. data/lib/mudguard/{error.rb → domain/error.rb} +3 -1
  17. data/lib/mudguard/domain/policies.rb +49 -0
  18. data/lib/mudguard/domain/source.rb +79 -0
  19. data/lib/mudguard/domain/source_policies.rb +8 -0
  20. data/lib/mudguard/domain/source_processor.rb +92 -0
  21. data/lib/mudguard/domain/texts.rb +42 -0
  22. data/lib/mudguard/infrastructure/cli/controller.rb +78 -0
  23. data/lib/mudguard/infrastructure/cli/notification_adapter.rb +26 -0
  24. data/lib/mudguard/infrastructure/cli/view.rb +14 -0
  25. data/lib/mudguard/infrastructure/persistence/.mudguard.template.yml +6 -0
  26. data/lib/mudguard/infrastructure/persistence/policy_file.rb +46 -0
  27. data/lib/mudguard/infrastructure/persistence/project_repository.rb +31 -0
  28. data/lib/mudguard/infrastructure/persistence/ruby_files.rb +39 -0
  29. data/lib/mudguard/infrastructure/rake/task.rb +28 -0
  30. data/lib/mudguard/version.rb +1 -1
  31. data/mudguard.gemspec +2 -1
  32. metadata +40 -11
  33. data/lib/mudguard/policies.rb +0 -23
  34. data/lib/mudguard/policy_file.rb +0 -17
  35. data/lib/mudguard/ruby_analyser.rb +0 -74
  36. data/lib/mudguard/ruby_files.rb +0 -17
  37. data/lib/tasks/gem.rake +0 -15
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mudguard
4
+ module Infrastructure
5
+ module Cli
6
+ # Handles user input
7
+ class View
8
+ def print(text)
9
+ puts text
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,6 @@
1
+ './**/*.rb':
2
+ # uncomment following lines to allow all dependencies
3
+ # - .*
4
+
5
+ # all code can depend on modules or constants defined in same module
6
+ - ^(::.+)(::[^:]+)* -> \1(::[^:]+)*$
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require_relative "../../domain/policies"
5
+ require_relative "../../domain/error"
6
+
7
+ module Mudguard
8
+ module Infrastructure
9
+ module Persistence
10
+ # A file containing the Mudguard-Policies
11
+ class PolicyFile
12
+ class << self
13
+ def read(project_path)
14
+ policy_file = File.join(project_path, ".mudguard.yml")
15
+ policy_exists = File.exist?(policy_file)
16
+
17
+ unless policy_exists
18
+ template_file = File.join(__dir__, ".mudguard.template.yml")
19
+ FileUtils.cp(template_file, policy_file)
20
+ end
21
+
22
+ read_yml(policy_file)
23
+ end
24
+
25
+ private
26
+
27
+ def read_yml(policy_file)
28
+ yaml_file = File.read(policy_file)
29
+ yaml = YAML.safe_load(yaml_file, [Symbol], [], policy_file) || {}
30
+ yaml.transform_values { |value| (value || []).map(&method(:unsymbolize)) }
31
+ rescue Psych::SyntaxError => e
32
+ raise Mudguard::Domain::Error, "#{policy_file} is invalid (#{e.message})"
33
+ end
34
+
35
+ def unsymbolize(dependency)
36
+ if dependency.is_a?(Symbol)
37
+ ":#{dependency}"
38
+ else
39
+ dependency
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "policy_file"
4
+ require_relative "ruby_files"
5
+ require_relative "../../domain/source_policies"
6
+
7
+ module Mudguard
8
+ module Infrastructure
9
+ module Persistence
10
+ # Provides access to the persisted source and policies
11
+ class ProjectRepository
12
+ class << self
13
+ def load_source_policies(project_path)
14
+ file = PolicyFile.read(project_path)
15
+ scopes = file.flat_map do |patterns, policies|
16
+ sources = RubyFiles.select(project_path, patterns: [patterns])
17
+ sources.flat_map { |s| { source: s, policies: policies } }
18
+ end
19
+
20
+ sources = scopes.group_by { |e| e[:source] }
21
+
22
+ sources.map do |source, group|
23
+ policies = group.flat_map { |r| r[:policies] }.uniq
24
+ Domain::SourcePolicies.new(source: source, policies: policies)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+ require "mudguard/domain/source"
5
+
6
+ module Mudguard
7
+ module Infrastructure
8
+ module Persistence
9
+ # Provides access to all ruby-files of a project
10
+ class RubyFiles
11
+ class << self
12
+ def select(project_path, patterns: nil)
13
+ project_exists = Dir.exist?(project_path)
14
+
15
+ unless project_exists
16
+ raise Mudguard::Domain::Error, "expected project #{project_path} doesn't exists"
17
+ end
18
+
19
+ patterns = [File.join("**", "*.rb")] if patterns.nil?
20
+ enumerate_files(project_path, patterns)
21
+ end
22
+
23
+ private
24
+
25
+ def enumerate_files(project_path, patterns)
26
+ project_path_name = Pathname.new(project_path)
27
+ ruby_files = patterns.map { |p| File.join(project_path, p) }
28
+ Dir.glob(ruby_files).map do |f|
29
+ file_path_name = Pathname.new(f)
30
+ diff_path = file_path_name.relative_path_from(project_path_name).to_s
31
+ Mudguard::Domain::Source.new(location: File.join("./", diff_path),
32
+ code_loader: -> { File.read(f) })
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rake"
4
+ require "rake/tasklib"
5
+ require_relative "../../application/application"
6
+ require_relative "../../infrastructure/cli/notification_adapter"
7
+ require_relative "../../infrastructure/cli/view"
8
+
9
+ module Mudguard
10
+ module Infrastructure
11
+ module Rake
12
+ # Provides Mudguard Rake Tasks
13
+ class Task < ::Rake::TaskLib
14
+ def initialize(project_dir: Dir.pwd)
15
+ @project_dir = project_dir
16
+
17
+ desc "Run Mudguard"
18
+ task(:mudguard) do
19
+ view = Mudguard::Infrastructure::Cli::View.new
20
+ notification = Mudguard::Infrastructure::Cli::NotificationAdapter.new(view: view)
21
+ ok = Application.check(@project_dir, notification)
22
+ abort unless ok
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mudguard
4
- VERSION = "0.1.4"
4
+ VERSION = "0.2.0"
5
5
  end
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
 
13
13
  spec.summary = "mudguard helps your ruby project not becoming a "\
14
14
  "'Big ball of mud'"
15
- spec.homepage = "https://gibhub.com/Enceradeira/mudguard"
15
+ spec.homepage = "https://github.com/Enceradeira/mudguard"
16
16
  spec.license = "MIT"
17
17
 
18
18
  spec.metadata["homepage_uri"] = spec.homepage
@@ -40,4 +40,5 @@ Gem::Specification.new do |spec|
40
40
  spec.add_development_dependency "rubocop", "~>0.80"
41
41
 
42
42
  spec.add_dependency "parser", "~>2.7"
43
+ spec.add_dependency "rake", "~> 13.0"
43
44
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mudguard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jorg Jenni
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-20 00:00:00.000000000 Z
11
+ date: 2020-06-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -150,6 +150,20 @@ dependencies:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
152
  version: '2.7'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rake
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '13.0'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '13.0'
153
167
  description:
154
168
  email:
155
169
  - jorg.jenni@jennius.co.uk
@@ -160,6 +174,7 @@ extra_rdoc_files: []
160
174
  files:
161
175
  - ".envrc"
162
176
  - ".gitignore"
177
+ - ".mudguard.yml"
163
178
  - ".rubocop.yml"
164
179
  - ".ruby-version"
165
180
  - CODE_OF_CONDUCT.md
@@ -171,23 +186,37 @@ files:
171
186
  - Rakefile
172
187
  - exe/mudguard
173
188
  - lib/mudguard.rb
174
- - lib/mudguard/error.rb
175
- - lib/mudguard/policies.rb
176
- - lib/mudguard/policy_file.rb
177
- - lib/mudguard/ruby_analyser.rb
178
- - lib/mudguard/ruby_files.rb
189
+ - lib/mudguard/application/application.rb
190
+ - lib/mudguard/domain/const_visitor.rb
191
+ - lib/mudguard/domain/consts.rb
192
+ - lib/mudguard/domain/dependencies.rb
193
+ - lib/mudguard/domain/dependency.rb
194
+ - lib/mudguard/domain/dependency_visitor.rb
195
+ - lib/mudguard/domain/error.rb
196
+ - lib/mudguard/domain/policies.rb
197
+ - lib/mudguard/domain/source.rb
198
+ - lib/mudguard/domain/source_policies.rb
199
+ - lib/mudguard/domain/source_processor.rb
200
+ - lib/mudguard/domain/texts.rb
201
+ - lib/mudguard/infrastructure/cli/controller.rb
202
+ - lib/mudguard/infrastructure/cli/notification_adapter.rb
203
+ - lib/mudguard/infrastructure/cli/view.rb
204
+ - lib/mudguard/infrastructure/persistence/.mudguard.template.yml
205
+ - lib/mudguard/infrastructure/persistence/policy_file.rb
206
+ - lib/mudguard/infrastructure/persistence/project_repository.rb
207
+ - lib/mudguard/infrastructure/persistence/ruby_files.rb
208
+ - lib/mudguard/infrastructure/rake/task.rb
179
209
  - lib/mudguard/version.rb
180
- - lib/tasks/gem.rake
181
210
  - lib/tasks/rubocop.rake
182
211
  - lib/tasks/test.rake
183
212
  - mudguard.gemspec
184
213
  - pkg/mudguard-0.1.0.gem
185
- homepage: https://gibhub.com/Enceradeira/mudguard
214
+ homepage: https://github.com/Enceradeira/mudguard
186
215
  licenses:
187
216
  - MIT
188
217
  metadata:
189
- homepage_uri: https://gibhub.com/Enceradeira/mudguard
190
- source_code_uri: https://gibhub.com/Enceradeira/mudguard
218
+ homepage_uri: https://github.com/Enceradeira/mudguard
219
+ source_code_uri: https://github.com/Enceradeira/mudguard
191
220
  post_install_message:
192
221
  rdoc_options: []
193
222
  require_paths:
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "ruby_analyser"
4
-
5
- module Mudguard
6
- # Contains the policies to be enforced
7
- class Policies
8
- def initialize(policies: [])
9
- @policies = policies.map { |l| l.gsub(/\s/, "") }.map { |p| /^#{p}/ }
10
- end
11
-
12
- def check(sources)
13
- sources.all? do |source|
14
- dependencies = RubyAnalyser.find_mod_dependencies(source)
15
- dependencies.all? do |d|
16
- @policies.any? do |p|
17
- d.match?(p)
18
- end
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "policies"
4
- require_relative "error"
5
-
6
- module Mudguard
7
- # A file containing the Mudguard-Policies
8
- class PolicyFile
9
- def self.read(policy_file)
10
- policy_exists = File.exist?(policy_file)
11
-
12
- raise Error, "expected policy file #{policy_file} doesn't exists" unless policy_exists
13
-
14
- Policies.new(policies: File.readlines(policy_file))
15
- end
16
- end
17
- end
@@ -1,74 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "parser/current"
4
-
5
- module Mudguard
6
- # Analyses Ruby-Source and returns extracted information
7
- class RubyAnalyser
8
- class << self
9
- def find_mod_dependencies(source)
10
- begin
11
- root = Parser::CurrentRuby.parse(source)
12
- rescue Parser::SyntaxError
13
- return []
14
- end
15
- return [] if root.nil?
16
-
17
- process(root)
18
- end
19
-
20
- private
21
-
22
- def process(node, module_name = "")
23
- case node
24
- when type?(:module)
25
- process_module(node.children)
26
- when type?(:class)
27
- process_class(node.children, module_name)
28
- when type?(:const)
29
- ["#{module_name}->#{find_const_name(node.children)}"]
30
- else
31
- ignore_and_continue(node, module_name)
32
- end
33
- end
34
-
35
- def ignore_and_continue(node, module_name)
36
- case node
37
- when children?
38
- node.children.flat_map { |c| process(c, module_name) }
39
- else
40
- []
41
- end
42
- end
43
-
44
- def process_module(children)
45
- module_name = find_const_name(children[0].children)
46
- process(children[1], module_name)
47
- end
48
-
49
- def process_class(children, module_name)
50
- process(children[1], module_name)
51
- end
52
-
53
- def find_const_name(children)
54
- return nil if children.nil?
55
-
56
- module_name = find_const_name(children[0]&.children)
57
- const_name = children[1].to_s
58
- if module_name.nil?
59
- const_name
60
- else
61
- "#{module_name}::#{const_name}"
62
- end
63
- end
64
-
65
- def children?
66
- ->(n) { n.respond_to?(:children) }
67
- end
68
-
69
- def type?(type)
70
- ->(n) { n.respond_to?(:type) && n.type == type }
71
- end
72
- end
73
- end
74
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mudguard
4
- # Provides access to all ruby-files of a project
5
- class RubyFiles
6
- class << self
7
- def all(project_path)
8
- project_exists = Dir.exist?(project_path)
9
-
10
- raise Error, "expected project #{project_path} doesn't exists" unless project_exists
11
-
12
- ruby_files = File.join(project_path, "**", "*.rb")
13
- Dir.glob(ruby_files).lazy
14
- end
15
- end
16
- end
17
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "rspec/core/rake_task"
4
- require "mudguard/version"
5
-
6
- namespace :gem do
7
- desc "Publishes the gem on rubygems.org"
8
- task publish: "gem:build" do
9
- exec("gem push mudguard-#{Mudguard::VERSION}.gem")
10
- end
11
- desc "Builds the gem"
12
- task :build do
13
- exec("gem build mudguard.gemspec")
14
- end
15
- end