archruby 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +32 -0
  6. data/Rakefile +1 -0
  7. data/archruby.gemspec +28 -0
  8. data/bin/archruby +20 -0
  9. data/bin/constraints_breaks.yml +29 -0
  10. data/constraints_breaks.yml +22 -0
  11. data/lib/archruby.rb +47 -0
  12. data/lib/archruby/architecture/architecture.rb +83 -0
  13. data/lib/archruby/architecture/config_definition.rb +66 -0
  14. data/lib/archruby/architecture/constraint_break.rb +22 -0
  15. data/lib/archruby/architecture/dependency.rb +11 -0
  16. data/lib/archruby/architecture/file_content.rb +24 -0
  17. data/lib/archruby/architecture/module_definition.rb +218 -0
  18. data/lib/archruby/architecture/parser.rb +58 -0
  19. data/lib/archruby/presenters/graph.rb +132 -0
  20. data/lib/archruby/presenters/text.rb +14 -0
  21. data/lib/archruby/presenters/yaml.rb +28 -0
  22. data/lib/archruby/ruby/core_library.rb +26 -0
  23. data/lib/archruby/ruby/parser.rb +409 -0
  24. data/lib/archruby/ruby/std_library.rb +22 -0
  25. data/lib/archruby/ruby/var_propagation.rb +46 -0
  26. data/lib/archruby/version.rb +3 -0
  27. data/spec/architecture/architecture_spec.rb +48 -0
  28. data/spec/architecture/config_definition_spec.rb +20 -0
  29. data/spec/architecture/constraint_break_spec.rb +22 -0
  30. data/spec/architecture/file_content_spec.rb +12 -0
  31. data/spec/architecture/module_definition_spec.rb +70 -0
  32. data/spec/architecture/parser_spec.rb +11 -0
  33. data/spec/archruby_spec.rb +10 -0
  34. data/spec/dummy_app/.gitignore +16 -0
  35. data/spec/dummy_app/Gemfile +45 -0
  36. data/spec/dummy_app/README.rdoc +28 -0
  37. data/spec/dummy_app/Rakefile +6 -0
  38. data/spec/dummy_app/app/assets/images/.keep +0 -0
  39. data/spec/dummy_app/app/assets/javascripts/application.js +16 -0
  40. data/spec/dummy_app/app/assets/stylesheets/application.css +13 -0
  41. data/spec/dummy_app/app/controllers/application_controller.rb +17 -0
  42. data/spec/dummy_app/app/controllers/concerns/.keep +0 -0
  43. data/spec/dummy_app/app/helpers/application_helper.rb +2 -0
  44. data/spec/dummy_app/app/mailers/.keep +0 -0
  45. data/spec/dummy_app/app/models/.keep +0 -0
  46. data/spec/dummy_app/app/models/concerns/.keep +0 -0
  47. data/spec/dummy_app/app/models/module_test.rb +5 -0
  48. data/spec/dummy_app/app/models/teste.rb +11 -0
  49. data/spec/dummy_app/app/models/user.rb +9 -0
  50. data/spec/dummy_app/app/views/layouts/application.html.erb +14 -0
  51. data/spec/dummy_app/app/views/view_test.rb +5 -0
  52. data/spec/dummy_app/bin/bundle +3 -0
  53. data/spec/dummy_app/bin/rails +4 -0
  54. data/spec/dummy_app/bin/rake +4 -0
  55. data/spec/dummy_app/config.ru +4 -0
  56. data/spec/dummy_app/config/application.rb +23 -0
  57. data/spec/dummy_app/config/boot.rb +4 -0
  58. data/spec/dummy_app/config/database.yml +25 -0
  59. data/spec/dummy_app/config/environment.rb +5 -0
  60. data/spec/dummy_app/config/environments/development.rb +29 -0
  61. data/spec/dummy_app/config/environments/production.rb +80 -0
  62. data/spec/dummy_app/config/environments/test.rb +36 -0
  63. data/spec/dummy_app/config/initializers/backtrace_silencers.rb +7 -0
  64. data/spec/dummy_app/config/initializers/filter_parameter_logging.rb +4 -0
  65. data/spec/dummy_app/config/initializers/inflections.rb +16 -0
  66. data/spec/dummy_app/config/initializers/mime_types.rb +5 -0
  67. data/spec/dummy_app/config/initializers/secret_token.rb +12 -0
  68. data/spec/dummy_app/config/initializers/session_store.rb +3 -0
  69. data/spec/dummy_app/config/initializers/wrap_parameters.rb +14 -0
  70. data/spec/dummy_app/config/locales/en.yml +23 -0
  71. data/spec/dummy_app/config/routes.rb +56 -0
  72. data/spec/dummy_app/db/seeds.rb +7 -0
  73. data/spec/dummy_app/lib/assets/.keep +0 -0
  74. data/spec/dummy_app/lib/fetch_facebook_info.rb +7 -0
  75. data/spec/dummy_app/lib/integracao_twitter.rb +5 -0
  76. data/spec/dummy_app/lib/tasks/.keep +0 -0
  77. data/spec/dummy_app/log/.keep +0 -0
  78. data/spec/dummy_app/public/404.html +58 -0
  79. data/spec/dummy_app/public/422.html +58 -0
  80. data/spec/dummy_app/public/500.html +57 -0
  81. data/spec/dummy_app/public/favicon.ico +0 -0
  82. data/spec/dummy_app/public/robots.txt +5 -0
  83. data/spec/dummy_app/test/controllers/.keep +0 -0
  84. data/spec/dummy_app/test/fixtures/.keep +0 -0
  85. data/spec/dummy_app/test/helpers/.keep +0 -0
  86. data/spec/dummy_app/test/integration/.keep +0 -0
  87. data/spec/dummy_app/test/mailers/.keep +0 -0
  88. data/spec/dummy_app/test/models/.keep +0 -0
  89. data/spec/dummy_app/test/test_helper.rb +15 -0
  90. data/spec/dummy_app/vendor/assets/javascripts/.keep +0 -0
  91. data/spec/dummy_app/vendor/assets/stylesheets/.keep +0 -0
  92. data/spec/fixtures/new_arch_definition.yml +32 -0
  93. data/spec/fixtures/ruby_example.rb +74 -0
  94. data/spec/ruby/parser_spec.rb +45 -0
  95. data/spec/ruby/var_propagation_spec.rb +22 -0
  96. data/spec/spec_helper.rb +1 -0
  97. metadata +295 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 045c1e67aaae360b110e2f9141b3b30bcc69c836
4
+ data.tar.gz: e4c92b6dfea42ffe218b4c5f26db3e8c1ad70021
5
+ SHA512:
6
+ metadata.gz: 67f954a1279803d686c882e72cbd16a5d692b585c8e841c4a2d4c7959b08eea72cd18f5ca2c8fb4b9af85c62962dde443766d4c71246544f617a43df6eb5c43c
7
+ data.tar.gz: ead18f3112485bdaa5a369d7e99fe82554407393cec180a72e27e70d763ec6001627314989da588b69429526f8d0c48fe4af6baa88ad4a4b6ddfdcb7e4f8718f
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in arch_checker.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Sergio Henrique
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,32 @@
1
+ # ArchChecker
2
+
3
+ This gem aims to verify whether the system architecture is being respected by the developers. The application architecture is defined by the Software Architect through a YML file. After defining the architecture, you can use the tool to analyze if any part of the architecture is being broken in the system. To do this analysis it is necessary to pass the architecture definition file and the root path of the application to the ArchChecker executable. The ArchChecker will do an static scan in the application and generate an yaml file containing the violations. One picture of the entire application with all the communications will be generated either.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'arch_checker'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install arch_checker
18
+
19
+ ## Usage
20
+
21
+ ### Defining the architecture
22
+
23
+ ### Invoking the arch_ckecker executable
24
+
25
+
26
+ ## Contributing
27
+
28
+ 1. Fork it
29
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
30
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
31
+ 4. Push to the branch (`git push origin my-new-feature`)
32
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'archruby/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "archruby"
8
+ spec.version = Archruby::VERSION
9
+ spec.authors = ["Sergio Henrique"]
10
+ spec.email = ["sergiohenriquetp@gmail.com"]
11
+ spec.description = %q{Compliance and Architectural Visualization in Ruby systems}
12
+ spec.summary = %q{Compliance and Architectural Visualization in Ruby systems}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_runtime_dependency "ruby_parser"
25
+ spec.add_runtime_dependency "sexp_processor"
26
+ spec.add_runtime_dependency "ruby-graphviz"
27
+
28
+ end
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path('../../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require 'archruby'
7
+
8
+ config_path = nil
9
+ app_root_path = nil
10
+ ARGV.each do |arg|
11
+ option, value = arg.split('=')
12
+ config_path = value if option.eql?('--arch_def_file')
13
+ app_root_path = value if option.eql?('--app_root_path')
14
+ end
15
+
16
+ arch_checker = Archruby::ExtractArchitecture.new(config_path, app_root_path)
17
+ constraints_breaks = arch_checker.verify
18
+
19
+ Archruby::Presenters::Yaml.new.render(arch_checker.architecture)
20
+ Archruby::Presenters::Graph.new.render(arch_checker.architecture)
@@ -0,0 +1,29 @@
1
+ ---
2
+ - divergence:
3
+ class_origin: TwitterController
4
+ line_origin: 21
5
+ class_target: Twitter::REST::Client
6
+ module_origin: controller
7
+ module_target: twitter
8
+ message: accessing a module not allowed
9
+ - divergence:
10
+ class_origin: Teste
11
+ line_origin: 3
12
+ class_target: SearchTerm
13
+ module_origin: view
14
+ module_target: model
15
+ message: accessing a module which is forbidden
16
+ - absence:
17
+ class_origin: TesteClass
18
+ line_origin:
19
+ class_target:
20
+ module_origin: model
21
+ module_target: activerecord
22
+ message: not implement a required module
23
+ - divergence:
24
+ class_origin: TwitterIntegration
25
+ line_origin: 19
26
+ class_target: PdfIntegration
27
+ module_origin: integracao_twitter
28
+ module_target: integracao_pdf
29
+ message: accessing a module not allowed
@@ -0,0 +1,22 @@
1
+ ---
2
+ - divergence:
3
+ class_origin: ApplicationController
4
+ line_origin: 1
5
+ class_target: ActionController::Base
6
+ module_origin: controller
7
+ module_target: ''
8
+ message: accessing a module not allowed
9
+ - divergence:
10
+ class_origin: ViewTest
11
+ line_origin: 3
12
+ class_target: User
13
+ module_origin: view
14
+ module_target: model
15
+ message: accessing a module which is forbidden
16
+ - absence:
17
+ class_origin: Teste
18
+ line_origin:
19
+ class_target:
20
+ module_origin: model
21
+ module_target: activerecord
22
+ message: not implement a required module
@@ -0,0 +1,47 @@
1
+ require "archruby/version"
2
+
3
+ require 'archruby/architecture/parser'
4
+ require 'archruby/architecture/config_definition'
5
+ require 'archruby/ruby/parser'
6
+ require 'archruby/ruby/std_library'
7
+ require 'archruby/ruby/core_library'
8
+ require 'archruby/ruby/var_propagation'
9
+ require 'archruby/architecture/file_content'
10
+ require 'archruby/architecture/module_definition'
11
+ require 'archruby/architecture/dependency'
12
+ require 'archruby/architecture/constraint_break'
13
+ require 'archruby/architecture/architecture'
14
+ require 'archruby/presenters/text'
15
+ require 'archruby/presenters/graph'
16
+ require 'archruby/presenters/yaml'
17
+
18
+ module Archruby
19
+ class ExtractArchitecture
20
+ attr_reader :architecture
21
+
22
+ def initialize config_file_path = "", base_directory = ""
23
+ @config_file_path = config_file_path
24
+ @base_directory = base_directory
25
+ @architecture_definition = Archruby::Architecture::Parser.new(File.expand_path(@config_file_path, __FILE__), @base_directory)
26
+ @architecture = Archruby::Architecture::Architecture.new(@architecture_definition.modules)
27
+ @constraints_breaks = []
28
+ end
29
+
30
+ def verify
31
+ @constraints_breaks = @architecture.verify
32
+ end
33
+ end
34
+
35
+ class Error < StandardError
36
+ def self.status_code(code)
37
+ define_method(:status_code) { code }
38
+ end
39
+
40
+ def self.msg(msg)
41
+ define_method(:msg) { msg }
42
+ end
43
+ end
44
+
45
+ class MultipleConstraints < Archruby::Error; status_code(2) ; msg("Allowed and Forbidden in same module definition") end
46
+ class ArchitectureNotVerified < Archruby::Error; status_code(3) ; msg("The architecture need to be verified first") end
47
+ end
@@ -0,0 +1,83 @@
1
+ module Archruby
2
+ module Architecture
3
+
4
+ class Architecture
5
+ attr_reader :constraints_breaks, :modules, :unknown_module
6
+
7
+ def initialize modules
8
+ @modules = modules
9
+ @constraints_breaks = []
10
+ @unknown_module = @modules.select{ |module_definition| module_definition.name == "unknown" }.first
11
+ end
12
+
13
+ def verify
14
+ @modules.each do |module_name|
15
+ contraints_breaks = module_name.verify_constraints(self)
16
+ if !contraints_breaks.empty?
17
+ @constraints_breaks << contraints_breaks
18
+ end
19
+ end
20
+ @constraints_breaks = @constraints_breaks.flatten
21
+ @constraints_breaks
22
+ end
23
+
24
+ def how_many_break module_name, module_target, constraint_type
25
+ raise ArchitectureNotVerified if @constraints_breaks.empty?
26
+ count = 0
27
+ @constraints_breaks.each do |constraint_break|
28
+ if constraint_break.type == constraint_type && constraint_break.module_origin == module_name && constraint_break.module_target == module_target
29
+ count += 1
30
+ end
31
+ end
32
+ count
33
+ end
34
+
35
+ def module_name class_name
36
+ module_name_to_return = ''
37
+ @modules.each do |module_name|
38
+ if module_name.is_mine? class_name
39
+ module_name_to_return = module_name.name
40
+ break
41
+ end
42
+ end
43
+ if module_name_to_return.eql? ''
44
+ @unknown_module.name
45
+ else
46
+ module_name_to_return
47
+ end
48
+ end
49
+
50
+ def how_many_access_to module_origin, module_dest
51
+ module_origin = search_module module_origin
52
+ count = 0
53
+ module_origin.classes_and_dependencies.each do |class_dependencies|
54
+ class_dependencies.each do |klass, dependencies|
55
+ dependencies.each do |dependency|
56
+ dependency_module_name = module_name dependency.class_name
57
+ if dependency_module_name == module_dest
58
+ count += 1
59
+ end
60
+ end
61
+ end
62
+ end
63
+ count
64
+ end
65
+
66
+ def is_ruby_internals? module_name
67
+ module_name == Archruby::Ruby::STD_LIB_NAME || module_name == Archruby::Ruby::CORE_LIB_NAME
68
+ end
69
+
70
+ private
71
+
72
+ def search_module module_name
73
+ @modules.each do |module_definition|
74
+ if module_definition.name == module_name
75
+ return module_definition
76
+ end
77
+ end
78
+ end
79
+
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,66 @@
1
+ module Archruby
2
+ module Architecture
3
+
4
+ class ConfigDefinition
5
+
6
+ ALLOWED_CONSTRAINTS = ['required', 'allowed', 'forbidden']
7
+
8
+ attr_reader :module_name, :files, :gems, :allowed_modules, :required_modules, :forbidden_modules
9
+
10
+ def initialize module_name, definitions
11
+ @module_name = module_name
12
+ @files = parse_files definitions['files']
13
+ @gems = parse_gems definitions['gems']
14
+ parse_constraints definitions
15
+ end
16
+
17
+ def parse_files files
18
+ files = '' if files.nil?
19
+ files = files.split(',')
20
+ normalize_string_spaces files
21
+ files
22
+ end
23
+
24
+ def parse_gems gems
25
+ gems = '' if gems.nil?
26
+ gems = gems.split(',')
27
+ normalize_string_spaces gems
28
+ gems
29
+ end
30
+
31
+ def parse_constraints definitions
32
+ check_constraints definitions
33
+ ALLOWED_CONSTRAINTS.each do |constraint|
34
+ constraint_definition = definitions[constraint]
35
+ constraint_definition = '' if constraint_definition.nil?
36
+ send "#{constraint}_modules=", normalize_string_spaces(constraint_definition.split(','))
37
+ end
38
+ end
39
+
40
+ def normalize_string_spaces array_of_strings
41
+ array_of_strings.map! {|element| element.strip }
42
+ end
43
+
44
+ def allowed_modules=(modules)
45
+ @allowed_modules = modules
46
+ end
47
+
48
+ def required_modules=(modules)
49
+ @required_modules = modules
50
+ end
51
+
52
+ def forbidden_modules=(modules)
53
+ @forbidden_modules = modules
54
+ end
55
+
56
+ private
57
+
58
+ def check_constraints definitions
59
+ raise MultipleConstraints if definitions['allowed'] && !definitions['allowed'].empty? && definitions['forbidden'] && !definitions['forbidden'].empty?
60
+ end
61
+
62
+
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,22 @@
1
+ module Archruby
2
+ module Architecture
3
+ class ConstraintBreak
4
+ attr_reader :type, :class_origin, :line_origin, :class_target, :module_origin,
5
+ :module_target, :msg
6
+
7
+ ABSENSE = "absence"
8
+ DIVERGENCE = "divergence"
9
+
10
+ def initialize options
11
+ @type = options[:type]
12
+ @class_origin = options[:class_origin]
13
+ @line_origin = options[:line_origin]
14
+ @class_target = options[:class_target]
15
+ @module_origin = options[:module_origin]
16
+ @module_target = options[:module_target]
17
+ @msg = options[:msg]
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ module Archruby
2
+ module Architecture
3
+ class Dependency
4
+ attr_reader :class_name, :line_number
5
+ def initialize class_name, line_number
6
+ @class_name = class_name.to_s
7
+ @line_number = line_number
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,24 @@
1
+ module Archruby
2
+ module Architecture
3
+ class FileContent
4
+
5
+ def initialize base_directory
6
+ # base_directory "/Users/sergiomiranda/Labs/ruby_arch_checker/arch_checker/spec/dummy_app/app"
7
+ @base_directory = base_directory
8
+ end
9
+
10
+ def all_content_from_directory directory
11
+ return if directory.nil? || directory.eql?("")
12
+ content = {}
13
+ file_paths = Dir.glob("#{@base_directory}/#{directory}")
14
+ file_paths.each do | file_path |
15
+ file = File.open(file_path, 'r')
16
+ file_name = File.basename(file_path, '.rb')
17
+ content[file_name] = file.read
18
+ end
19
+ content
20
+ end
21
+
22
+ end
23
+ end
24
+ end