mudguard 0.1.4 → 0.2.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.
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