axr 0.6.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 07cc36c3d0e6ff1efe1a1519a68cf8c9dacdf0ac8f61c73fdda1e69da7fc179c
4
- data.tar.gz: aaca58deb866a1709cba78aeac7f264e3faa15476cefb1e24f761419aba15381
3
+ metadata.gz: 1c1451590219c2fdac14e2352ef0a6af39dd388b60cc8caa5c1a86fac06e901a
4
+ data.tar.gz: 54b6490d145aff76491361d3cfa05c892aeb4ada42f743617ebe0598a0e428bc
5
5
  SHA512:
6
- metadata.gz: 76674bdd4990df3982fb13c4061e5494e55578bf2c612f1d27c6f0b04206adc1dc9e6879b3bb405155b989fa2b44d002f8b004f995cae1064e25d9b9236e5b63
7
- data.tar.gz: 1473e443635bd793f7a7dfc9e261493d8076d0cbfad011e128ba0caf9ba622c20d1e2d07dd5e5f3d63bb7578fce564b5e7c55efc14312ff84637d5b00024505f
6
+ metadata.gz: 464f7640c98b92353df69f233210d896a7036a9b0e19a723e3b1480743e93bcfd40cd2c79affb4469eb48a1ffaf485984a95b0f8677c2384a77a30cbfac58468
7
+ data.tar.gz: 878bc7e2300eea09534bae0e33d24e303903a1b7be0479f12207da6e35822cb825460ee595c74a7955e7b507e44094e85357119367c025a92ea4bc7d3c200987
data/.gitignore CHANGED
@@ -7,6 +7,10 @@
7
7
  /spec/reports/
8
8
  /tmp/
9
9
 
10
+ # development files
11
+ .ruby-gemset
12
+ .ruby-version
13
+
10
14
  # rspec failure tracking
11
15
  .rspec_status
12
16
  *.gem
@@ -1,10 +1,11 @@
1
- require: rubocop-rails
1
+ require: rubocop
2
2
 
3
3
  AllCops:
4
4
  TargetRubyVersion: 2.6
5
5
  Exclude:
6
6
  - bin/*
7
7
  - Guardfile
8
+ - vendor/**/*
8
9
 
9
10
  Style/Documentation:
10
11
  Enabled: false
@@ -12,12 +13,23 @@ Style/Documentation:
12
13
  Metrics/LineLength:
13
14
  Max: 120
14
15
 
16
+ Metrics/AbcSize:
17
+ Max: 20
18
+
15
19
  Metrics/BlockLength:
16
20
  ExcludedMethods: [
17
- 'describe', 'xdescribe', 'context', 'xcontext', 'it', 'xit', 'let', 'before', 'after', 'aggregate_failures'
21
+ 'describe',
22
+ 'xdescribe',
23
+ 'context',
24
+ 'xcontext',
25
+ 'it',
26
+ 'xit',
27
+ 'let',
28
+ 'before',
29
+ 'after',
30
+ 'aggregate_failures'
18
31
  ]
19
32
 
20
-
21
33
  Metrics/MethodLength:
22
34
  Max: 15
23
35
 
@@ -1,7 +1,13 @@
1
1
  ---
2
- sudo: false
3
2
  language: ruby
4
3
  cache: bundler
5
4
  rvm:
6
- - 2.6.3
7
- before_install: gem install bundler -v 2.0.2
5
+ - 2.5.7
6
+ - 2.6.5
7
+ - 2.7.0
8
+ before_install:
9
+ - gem install bundler
10
+ - bundle install
11
+ script:
12
+ - bundle exec rubocop
13
+ - bundle exec rspec
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- axr (0.6.0)
4
+ axr (0.8.0)
5
5
  colorize (~> 0.8.1)
6
6
  thor (~> 0.20)
7
7
 
@@ -12,7 +12,7 @@ GEM
12
12
  coderay (1.1.2)
13
13
  colorize (0.8.1)
14
14
  diff-lcs (1.3)
15
- ffi (1.11.1)
15
+ ffi (1.12.2)
16
16
  formatador (0.2.5)
17
17
  guard (2.16.1)
18
18
  formatador (>= 0.2.4)
@@ -29,39 +29,39 @@ GEM
29
29
  guard-compat (~> 1.1)
30
30
  rspec (>= 2.99.0, < 4.0)
31
31
  jaro_winkler (1.5.4)
32
- listen (3.2.0)
32
+ listen (3.2.1)
33
33
  rb-fsevent (~> 0.10, >= 0.10.3)
34
34
  rb-inotify (~> 0.9, >= 0.9.10)
35
- lumberjack (1.0.13)
35
+ lumberjack (1.2.4)
36
36
  method_source (0.9.2)
37
37
  nenv (0.3.0)
38
38
  notiffany (0.1.3)
39
39
  nenv (~> 0.1)
40
40
  shellany (~> 0.0)
41
- parallel (1.18.0)
42
- parser (2.6.5.0)
41
+ parallel (1.19.1)
42
+ parser (2.7.0.5)
43
43
  ast (~> 2.4.0)
44
44
  pry (0.12.2)
45
45
  coderay (~> 1.1.0)
46
46
  method_source (~> 0.9.0)
47
47
  rainbow (3.0.0)
48
- rake (10.5.0)
48
+ rake (12.3.3)
49
49
  rb-fsevent (0.10.3)
50
- rb-inotify (0.10.0)
50
+ rb-inotify (0.10.1)
51
51
  ffi (~> 1.0)
52
52
  rspec (3.9.0)
53
53
  rspec-core (~> 3.9.0)
54
54
  rspec-expectations (~> 3.9.0)
55
55
  rspec-mocks (~> 3.9.0)
56
- rspec-core (3.9.0)
57
- rspec-support (~> 3.9.0)
58
- rspec-expectations (3.9.0)
56
+ rspec-core (3.9.1)
57
+ rspec-support (~> 3.9.1)
58
+ rspec-expectations (3.9.1)
59
59
  diff-lcs (>= 1.2.0, < 2.0)
60
60
  rspec-support (~> 3.9.0)
61
- rspec-mocks (3.9.0)
61
+ rspec-mocks (3.9.1)
62
62
  diff-lcs (>= 1.2.0, < 2.0)
63
63
  rspec-support (~> 3.9.0)
64
- rspec-support (3.9.0)
64
+ rspec-support (3.9.2)
65
65
  rubocop (0.76.0)
66
66
  jaro_winkler (~> 1.5.1)
67
67
  parallel (~> 1.10)
@@ -72,7 +72,7 @@ GEM
72
72
  ruby-progressbar (1.10.1)
73
73
  shellany (0.0.1)
74
74
  thor (0.20.3)
75
- unicode-display_width (1.6.0)
75
+ unicode-display_width (1.6.1)
76
76
 
77
77
  PLATFORMS
78
78
  ruby
@@ -82,7 +82,7 @@ DEPENDENCIES
82
82
  bundler (~> 2.0)
83
83
  guard-rspec (~> 4.7.3)
84
84
  pry (~> 0.12.2)
85
- rake (~> 10.0)
85
+ rake (~> 12.3.3)
86
86
  rspec (~> 3.0)
87
87
  rubocop (~> 0.76.0)
88
88
 
data/README.md CHANGED
@@ -1,31 +1,44 @@
1
1
  # AXR
2
2
 
3
- ### Ruby applications architecture for simplicity and team adoption
3
+ **Ruby architecture for simplicity and team adoption**
4
4
 
5
- Architecture is hard. It’s very easy to build a complex system; much harder to build a simple and adaptable one. The code doesn't matter and coding for the sake of writing code is foolish.
5
+ Architecture's hard. It’s very easy to build a complex system. Much harder to build a simple and adaptable solution. The code doesn't matter. Coding for the sake of writing code is foolish.
6
6
 
7
- Few of us get to write software that survives 5-10 years or longer. 90% of our work is garbage that becomes obsolete 1-3 years after release. Most of our work hours are wasted on features that never get shipped.
7
+ Only a few of us get to write software that survives 5-10 years or longer. 90% of our work is garbage that becomes obsolete in 1-3 years after release. Most of our work hours are wasted on features that will never be useful.
8
8
 
9
- This is just reality.
9
+ This is just a reality.
10
10
 
11
- (c) Me
12
11
 
13
- ### Setup
12
+ (c) Volodya Sveredyuk
14
13
 
15
- ```sh
16
- gem install axr
17
- ```
14
+ ## Motivation
15
+ Application engineering it's always about abstractions and how they describe the real world and business which pays our salaries for coding something that might improve it. Maybe. Sometimes.
16
+
17
+ I hate doing something alone. I am a team player and as a team player, I prefer conventions over configuration. But this is not working with knowledge responsibility segregation inside the software app. In the Ruby world (especially Rails) it's so easy to add a new feature. Just add one line, one dependency, one callback and now you share knowledge about one entity into another entity. More dependencies - more spaghetti and legacy that in future we should REWRITE EVERYTHING!
18
+
19
+ <img src="docs/images/rewrite.png" alt="drawing" width="500"/>
20
+
21
+ Architecture's about knowledge responsibility and not the code.
22
+
23
+ The worst thing that even we write the architecture document wherein a convenient way to agree on architecture and layers and entities, etc - We are not protected from violation of these conventions.
18
24
 
19
- or in your Gemfile:
25
+ And this the place where AxR comes on the stage.
26
+
27
+ Please, welcome the **DSL** that helps:
28
+ 1. Describes your application layers (modules)
29
+ 2. Defines knowledge responsibilities between them
30
+ 3. Checks if you did not violate anything
31
+
32
+ ## Setup
33
+
34
+ In your Gemfile
20
35
  ```ruby
21
- gem 'axr', '~> 0.5'
36
+ gem 'axr'
22
37
  ```
23
38
 
24
- ```sh
25
- bundle install
26
- ```
39
+ ## DSL
27
40
 
28
- Somewhere in your ruby app:
41
+ In your ruby app: (for rails app put it into `config/initializers/axr.rb` file)
29
42
  ```ruby
30
43
  require 'axr'
31
44
 
@@ -36,6 +49,51 @@ AxR.app.define do
36
49
  end
37
50
  ```
38
51
 
52
+ By default, layers will get level from top to bottom.
53
+ ```
54
+ Api -> 0
55
+ YourBusinessLogic -> 1
56
+ Repo -> 2
57
+ ```
58
+
59
+ Layers with lower-level have less isolation.
60
+
61
+ - `Api` knows about `YourBusinessLogic` and `Repo`
62
+ - `YourBusinessLogic` knows about `Repo` but don't know anything about `Api`
63
+ - `Repo` fully isolated and don't familiar with `Api` and `YourBusinessLogic`
64
+
65
+ **Options**
66
+
67
+ ```ruby
68
+ require 'axr'
69
+
70
+ AxR.app.define do
71
+ layer 'A'
72
+ layer 'B', familiar_with: 'C'
73
+ layer 'C', familiar_with: 'B'
74
+ layer 'D', isolated: true
75
+ layer 'E', isolated: true
76
+ end
77
+ ```
78
+
79
+ ```ruby
80
+
81
+ # app.define options
82
+ AxR.app.define(isolated: true) # All layers will be isolated by default
83
+ AxR.app.define(familiar_with: ['D', 'E') # All layers will be familiar with D and E by default
84
+
85
+ # layer options
86
+ familiar_with: [...] # Can operate with other layers
87
+ isolated: true # 100% isolated and should not operate with other layers
88
+ isolated: true, familiar_with: [...] # Isolated from all except familiars
89
+ ```
90
+
91
+ Can organize knowledge structure like:
92
+
93
+ <img src="docs/images/abcde_example.png" alt="drawing" width="500"/>
94
+
95
+ ## CLI
96
+
39
97
  Run `AxR` checker in console
40
98
  ```sh
41
99
  axr check . --load path/to/you/app/autoload.rb
@@ -56,8 +114,38 @@ Run for a specific file
56
114
  axr lib/adapters/youtube.rb
57
115
  ```
58
116
 
59
- ### How it works
60
- ...TODO
117
+ Finish scanning with status code 1 in case of any warnings (you can use in CI environment to fail pipeline step)
118
+ ```sh
119
+ axr check --exit-on-warnings
120
+ ```
121
+
122
+ ## More examples
123
+
124
+ **ERP system**
125
+
126
+ <img src="docs/images/erp_example.png" alt="drawing" width="500"/>
127
+
128
+ ```ruby
129
+ if Rails.env.development? || Rails.env.test?
130
+ require 'axr'
131
+
132
+ AxR.app.define(isolated: true) do
133
+ layer 'UI', familiar_with: %w[Docs Inventory Production]
134
+ layer 'API', familiar_with: %w[Docs Inventory Production]
135
+ layer 'Docs', familiar_with: %w[Inventory Accounts Repo]
136
+ layer 'Accounts', familiar_with: %w[Repo]
137
+ layer 'Inventory', familiar_with: %w[Repo]
138
+ layer 'Production', familiar_with: %w[Repo]
139
+ layer 'Repo'
140
+ end
141
+ end
142
+
143
+ ```
61
144
 
62
145
  ### TODO
146
+ - Ignore vendor or any other directories dir as configuration
63
147
  - Add sublayers
148
+ - Add rubocop cop
149
+ - Add more app examples
150
+ - Migrate to AST analyzer
151
+
@@ -30,12 +30,12 @@ Gem::Specification.new do |spec|
30
30
  spec.require_paths = 'lib'
31
31
 
32
32
  spec.add_dependency 'colorize', '~> 0.8.1'
33
- spec.add_dependency 'thor', '~> 0.20'
33
+ spec.add_dependency 'thor', '~> 0.20'
34
34
 
35
- spec.add_development_dependency 'bundler', '~> 2.0'
35
+ spec.add_development_dependency 'bundler', '~> 2.0'
36
36
  spec.add_development_dependency 'guard-rspec', '~> 4.7.3'
37
- spec.add_development_dependency 'pry', '~> 0.12.2'
38
- spec.add_development_dependency 'rake', '~> 10.0'
39
- spec.add_development_dependency 'rspec', '~> 3.0'
40
- spec.add_development_dependency 'rubocop', '~> 0.76.0'
37
+ spec.add_development_dependency 'pry', '~> 0.12.2'
38
+ spec.add_development_dependency 'rake', '~> 12.3.3'
39
+ spec.add_development_dependency 'rspec', '~> 3.0'
40
+ spec.add_development_dependency 'rubocop', '~> 0.76.0'
41
41
  end
Binary file
@@ -37,8 +37,8 @@ module AxR
37
37
  dep = layers.find { |l| l.name.to_s == dependncy.to_s }
38
38
 
39
39
  return false unless ctx && dep
40
- return false if ctx.isolated?
41
- return true if ctx.familiar_with.map(&:to_s).include?(dependncy.to_s)
40
+ return false if ctx.isolated? && ctx.familiar_with.empty?
41
+ return true if ctx.familiar_with.map(&:to_s).include?(dependncy.to_s)
42
42
 
43
43
  ctx.level < dep.level
44
44
  end
@@ -4,15 +4,18 @@ require 'thor'
4
4
 
5
5
  module AxR
6
6
  class CLI < Thor
7
- desc 'check PATH', 'Start AxR runner'
7
+ desc 'check PATH', 'Start AxR runner'
8
+ desc '--load APP_INIT_PATH', 'Specify file to load your ruby application'
9
+ desc '--exit-on-warnings', 'Finish with status code 1 on any warnings'
8
10
 
9
- option :format # TODO: Add formats
10
- option :load # TODO: Add formats
11
+ option :format # TODO: Add more output formats
12
+ option :load
13
+ option :'exit-on-warnings'
11
14
 
12
15
  def check(pattern = nil)
13
16
  $LOAD_PATH << Dir.pwd
14
17
  require options['load'] if options['load']
15
- AxR::Runner.new(pattern).invoke
18
+ AxR::Runner.new(pattern, exit_on_warnings: !options['exit-on-warnings'].nil?).invoke
16
19
  end
17
20
  end
18
21
  end
@@ -7,33 +7,33 @@ module AxR
7
7
  class Runner
8
8
  DOT_RB = '.rb'
9
9
 
10
- attr_reader :target, :formatter
10
+ attr_reader :target, :formatter, :exit_on_warnings
11
11
 
12
- def initialize(target = nil, formatter: AxR::Formatters::Default.new)
13
- @target = target
14
- @formatter = formatter
12
+ def initialize(target = nil, formatter: AxR::Formatters::Default.new, exit_on_warnings: false)
13
+ @target = target
14
+ @formatter = formatter
15
+ @exit_on_warnings = exit_on_warnings
15
16
  end
16
17
 
18
+ alias exit_on_warnings? exit_on_warnings
19
+
17
20
  def invoke
18
21
  files_with_warnings = files_to_scan.each_with_object({}) do |file_path, issues|
19
- scan_result = AxR::Scanner.new(file_path: file_path).scan
22
+ scan_result = AxR::Scanner.new(source: File.open(file_path)).scan
20
23
  issues[file_path] = scan_result.warnings if scan_result.warnings.any?
24
+
21
25
  formatter.single_file(scan_result, file_path)
22
26
  end
23
27
 
24
28
  formatter.summary(files_to_scan, files_with_warnings)
25
29
 
26
- # exit 1 if files_with_warnings.any?
30
+ exit 1 if exit_on_warnings? && files_with_warnings.any?
27
31
 
28
32
  files_with_warnings
29
33
  end
30
34
 
31
35
  def files_to_scan
32
- @files_to_scan ||= if scan_single_file?
33
- [target]
34
- else
35
- Dir.glob("#{target_dir}**/*.rb")
36
- end
36
+ @files_to_scan ||= scan_single_file? ? [target] : Dir.glob("#{target_dir}**/*#{DOT_RB}")
37
37
  end
38
38
 
39
39
  private
@@ -5,10 +5,10 @@ require_relative 'scanner/warning'
5
5
 
6
6
  module AxR
7
7
  class Scanner
8
- attr_reader :file_path, :context, :dependecies, :warnings
8
+ attr_reader :source, :context, :dependecies, :warnings
9
9
 
10
- def initialize(file_path:)
11
- @file_path = file_path
10
+ def initialize(source: [])
11
+ @source = source
12
12
  @dependecies = []
13
13
  @warnings = []
14
14
  @context = nil
@@ -16,18 +16,19 @@ module AxR
16
16
 
17
17
  # rubocop:disable Metrics/AbcSize
18
18
  def scan
19
- File.open(file_path).each.with_index do |line, index|
19
+ source.each.with_index do |line, index|
20
20
  loc_num = index + 1
21
21
 
22
22
  line_detection = AxR.app.layer_names.detect { |layer| line.include?(layer) }
23
23
  line_detection = check_space_before(line, line_detection)
24
- context_detection = AxR.app.layer_names.detect { |layer| line.include?("module #{layer}") }
24
+ line_detection = nil if context && module_definition?(line, line_detection)
25
+ context_detection = AxR.app.layer_names.detect { |layer| module_definition?(line, layer) }
25
26
 
26
- next unless line_detection || context_detection
27
+ next unless context_detection || line_detection
27
28
 
28
29
  detect_context(context_detection, line, loc_num) if context_detection && !context
29
30
  detect_dependency(line_detection, line, loc_num)
30
- detect_warning(line_detection, line, loc_num) if context
31
+ detect_warning(line_detection, line, loc_num) if context && line_detection
31
32
  end
32
33
 
33
34
  self
@@ -66,5 +67,11 @@ module AxR
66
67
 
67
68
  line_detection if line[line.index(line_detection) - 1] == SPACE
68
69
  end
70
+
71
+ MODULE = 'module'
72
+
73
+ def module_definition?(line, layer)
74
+ line.include?("#{MODULE} #{layer}")
75
+ end
69
76
  end
70
77
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AxR
4
- VERSION = '0.6.0'
4
+ VERSION = '0.8.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: axr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Volodya Sveredyuk
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-11-30 00:00:00.000000000 Z
11
+ date: 2020-08-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '10.0'
89
+ version: 12.3.3
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '10.0'
96
+ version: 12.3.3
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rspec
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -145,6 +145,9 @@ files:
145
145
  - axr.gemspec
146
146
  - bin/console
147
147
  - bin/setup
148
+ - docs/images/abcde_example.png
149
+ - docs/images/erp_example.png
150
+ - docs/images/rewrite.png
148
151
  - exe/axr
149
152
  - lib/axr.rb
150
153
  - lib/axr/app.rb
@@ -180,7 +183,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
180
183
  - !ruby/object:Gem::Version
181
184
  version: '0'
182
185
  requirements: []
183
- rubygems_version: 3.0.6
186
+ rubygems_version: 3.1.2
184
187
  signing_key:
185
188
  specification_version: 4
186
189
  summary: Code checker for AxR compliance.