lapidarius 1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0c2f5e0adba9a26b9c587019623572558703d340
4
+ data.tar.gz: 57c04cf09af054ce51b002eace5c90ee4a77000b
5
+ SHA512:
6
+ metadata.gz: 4321b2c5a80c88fd794683dc3a9a4905beda4e9fcc655c0cd6fa1445fb023456bdb22d38d8f4e68a5c8e9fcf406ceefa248c0923355eefff708dc69f50577852
7
+ data.tar.gz: 45033c48b91c70b94e6c60af650084e0a38945aae9942e7d8ef8ab0962924f9c08b8bf9ebc5f55aa6cf0f39e82c9e77824595d500c04bb66500c281ba7017253
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.1.8
5
+ - 2.2.1
6
+ - 2.3.1
7
+ before_install: gem install bundler -v 1.12.5
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gem_dependencies.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+ ## Table of Contents
2
+
3
+ * [Scope](#scope)
4
+ * [Alternatives](#alternatives)
5
+ * [gem dep](#gem-dep)
6
+ * [bundle viz](#bundle-viz)
7
+ * [Usage](#usage)
8
+ * [Unique dependencies](#unique-dependencies)
9
+ * [Recursive print](#recursive-print)
10
+ * [Warning](#warning)
11
+
12
+ ## Scope
13
+ This gem is aimed to list recursively the **runtime dependencies** footprint of the specified gem.
14
+
15
+ ### Alternatives
16
+ Some alternatives exists:
17
+
18
+ #### gem dep
19
+ The standard *gem dep* command just unearth one level of dependencies.
20
+
21
+ #### bundle viz
22
+ The *bundle viz* command relies on the Gemfile and the [graphviz](http://www.graphviz.org/) library to generate a visual representation of the gem inter-dependencies.
23
+ While it is great to visualize inter-dependencies, i have hard times figuring out gem's runtime footprint.
24
+
25
+ ## Usage
26
+ The library relies on the *Gem::Commands::DependencyCommand* class (the one invoked by the *gem dep* command line), invoking it recursively to deeply fetch dependencies.
27
+
28
+ ### Unique dependencies
29
+ The command outcome includes all of the unique (by name) nested runtime dependencies:
30
+ ```
31
+ $ ./bin/lapidarius --gem=grape
32
+
33
+ grape (0.17.0) 20
34
+ ------------------------------
35
+ activesupport (>= 0)
36
+ builder (>= 0)
37
+ hashie (>= 2.1.0)
38
+ multi_json (>= 1.3.2)
39
+ multi_xml (>= 0.5.2)
40
+ mustermann19 (~> 0.4.3)
41
+ rack (>= 1.3.0)
42
+ rack-accept (>= 0)
43
+ virtus (>= 1.0.0)
44
+ concurrent-ruby (>= 1.0.2, ~> 1.0)
45
+ i18n (~> 0.7)
46
+ minitest (~> 5.1)
47
+ tzinfo (~> 1.1)
48
+ thread_safe (~> 0.1)
49
+ enumerable-lazy (>= 0)
50
+ axiom-types (~> 0.1)
51
+ coercible (~> 1.0)
52
+ descendants_tracker (>= 0.0.3, ~> 0.0)
53
+ equalizer (>= 0.0.9, ~> 0.0)
54
+ ice_nine (~> 0.11.0)
55
+
56
+ ```
57
+
58
+ ### Recursive print
59
+ To print dependencies hierarchy recursively, provide the *--recursive* flag. Duplicates are not counted:
60
+ ```
61
+ $ ./bin/lapidarius --gem=sinatra --recursive
62
+
63
+ sinatra (1.4.7) 3
64
+ ------------------------------
65
+ rack (~> 1.5)
66
+ rack-protection (~> 1.4)
67
+ rack (>= 0)
68
+ tilt (< 3, >= 1.3)
69
+
70
+ ```
71
+
72
+ ### Warning
73
+ Consider only the gems installed on your system are scanned for their own dependencies, no remote fetching is performed.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:spec) do |t|
5
+ t.libs << "spec"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["spec/**/*_spec.rb"]
8
+ end
9
+
10
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "lapidarius"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/lapidarius ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ lib = File.expand_path("../../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require "lapidarius"
6
+
7
+ Lapidarius::CLI.new(ARGV.clone).call
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "lapidarius/version"
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "lapidarius"
8
+ s.version = Lapidarius::VERSION
9
+ s.authors = ["costajob"]
10
+ s.email = ["costajob@gmail.com"]
11
+ s.homepage = "https://github.com/costajob/lapidarius"
12
+ s.summary = "A tiny library to visualize and count gem dependencies recursively"
13
+ s.license = "MIT"
14
+ s.required_ruby_version = ">= 2.1.8"
15
+
16
+ s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ s.bindir = "exe"
18
+ s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_development_dependency "bundler", "~> 1.12"
22
+ s.add_development_dependency "rake", "~> 10.0"
23
+ s.add_development_dependency "minitest", "~> 5.0"
24
+ end
data/lib/lapidarius.rb ADDED
@@ -0,0 +1,5 @@
1
+ lib = File.expand_path("../../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ require "lapidarius/version"
5
+ require "lapidarius/cli"
@@ -0,0 +1,51 @@
1
+ require "optparse"
2
+ require "lapidarius/cutter"
3
+ require "lapidarius/renderer"
4
+
5
+ module Lapidarius
6
+ class CLI
7
+ class NoGemError < ArgumentError; end
8
+
9
+ def initialize(args, io = STDOUT)
10
+ @args = args
11
+ @io = io
12
+ @gem = nil
13
+ @recursive = nil
14
+ end
15
+
16
+ def call(cmd_klass = Command)
17
+ parser.parse!(@args)
18
+ fail NoGemError, "please specify the name of an installed gem!" unless @gem
19
+ gem = cutter(cmd_klass).call
20
+ renderer(gem).call(@io)
21
+ end
22
+
23
+ private def parser
24
+ OptionParser.new do |opts|
25
+ opts.banner = "Usage: ./bin/lapidarius --gem=sinatra --recursive"
26
+
27
+ opts.on("-gGEM", "--gem=GEM", "The gem name to scan") do |gem|
28
+ @gem = gem
29
+ end
30
+
31
+ opts.on("-r", "--recursive", "Print dependencies recursively") do |recursive|
32
+ @recursive = recursive
33
+ end
34
+
35
+ opts.on("-h", "--help", "Prints this help") do
36
+ @io.puts opts
37
+ exit
38
+ end
39
+ end
40
+ end
41
+
42
+ private def cutter(cmd_klass)
43
+ @cutter = Lapidarius::Cutter.new(gem: @gem, cmd_klass: cmd_klass)
44
+ end
45
+
46
+ private def renderer(gem)
47
+ Lapidarius::Renderer::new(gem: gem, recursive: @recursive)
48
+ end
49
+ end
50
+ end
51
+
@@ -0,0 +1,18 @@
1
+ require "rubygems/commands/dependency_command"
2
+ require "lapidarius/ui"
3
+
4
+ module Lapidarius
5
+ class Command
6
+ def initialize(dep_klass: ::Gem::Commands::DependencyCommand, ui_klass: UI)
7
+ @dep = dep_klass.new
8
+ @dep.ui = ui_klass.new
9
+ end
10
+
11
+ def call(gem)
12
+ @dep.ui.clear!
13
+ @dep.invoke(gem)
14
+ @dep.ui.out
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,38 @@
1
+ require "lapidarius/gem"
2
+ require "lapidarius/command"
3
+
4
+ module Lapidarius
5
+ class Cutter
6
+ DEVELOPMENT = "development"
7
+
8
+ def initialize(gem:, cmd_klass: Command)
9
+ @gem = gem
10
+ @cmd = cmd_klass.new
11
+ end
12
+
13
+ def call(src = cmd, gem = nil)
14
+ tokens = tokenize(src)
15
+ token = tokens.shift
16
+ gem ||= Gem.factory(token)
17
+ tokens.each do |t|
18
+ dep = Gem.factory(t)
19
+ next unless dep
20
+ gem << dep
21
+ call(cmd(dep.name), dep)
22
+ end
23
+ gem
24
+ end
25
+
26
+ private def tokenize(src)
27
+ src = src.split(/\n\n/).first
28
+ src.split("\n").tap do |tokens|
29
+ tokens.map!(&:strip)
30
+ tokens.reject! { |token| token.match(/#{DEVELOPMENT}/) }
31
+ end
32
+ end
33
+
34
+ private def cmd(gem = @gem)
35
+ @cmd.call(gem)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,70 @@
1
+ module Lapidarius
2
+ class Gem
3
+ class KindError < ArgumentError; end
4
+
5
+ LEVEL_DEPTH = 5
6
+
7
+ def self.factory(name)
8
+ name.match(/Gem ([a-z0-9\-_]+)-(\d{1,2}\.\d{1,3}\.\d{1,2})/) do |m|
9
+ return new(name: m[1], version: m[2])
10
+ end
11
+ name.match(/([a-z0-9\-_]+) \(([0-9~<>=, \.]+)\)/) do |m|
12
+ return new(name: m[1], version: m[2])
13
+ end
14
+ end
15
+
16
+ attr_reader :name, :version, :deps
17
+
18
+ def initialize(name:, version:, deps: [])
19
+ @name = name
20
+ @version = version
21
+ @deps = deps
22
+ end
23
+
24
+ def <<(dep)
25
+ fail KindError, "#{dep.inspect} is not a valid gem" unless gem?(dep)
26
+ @deps << dep
27
+ end
28
+
29
+ def ==(gem)
30
+ return false unless gem?(gem)
31
+ gem.name == name && gem.version == version
32
+ end
33
+
34
+ def to_s(recursive: false)
35
+ return fullname unless recursive
36
+ fullname.tap do |s|
37
+ deps.each do |dep|
38
+ s << "\n"
39
+ s << indentation
40
+ s << dep.to_s(recursive: recursive)
41
+ end
42
+ end
43
+ end
44
+
45
+ def fullname
46
+ "#{name} (#{version})"
47
+ end
48
+
49
+ def deep_count
50
+ flatten_deps.size
51
+ end
52
+
53
+ protected def flatten_deps
54
+ deps.reduce(deps) do |acc, dep|
55
+ acc.concat dep.flatten_deps
56
+ end.tap do |deps|
57
+ deps.flatten!
58
+ deps.uniq!(&:name)
59
+ end
60
+ end
61
+
62
+ private def indentation
63
+ " " * (caller.size / LEVEL_DEPTH)
64
+ end
65
+
66
+ private def gem?(gem)
67
+ %i{name version deps}.all? { |msg| gem.respond_to?(msg) }
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,39 @@
1
+ module Lapidarius
2
+ class Renderer
3
+ class NoEntGemError< ArgumentError; end
4
+
5
+ def initialize(gem:, recursive: false)
6
+ fail NoEntGemError, "gem not found on this system!" unless gem
7
+ @gem = gem
8
+ @recursive = recursive
9
+ @out = []
10
+ end
11
+
12
+ def call(io = STDOUT)
13
+ io.puts out
14
+ end
15
+
16
+ def out
17
+ header
18
+ body
19
+ @out
20
+ end
21
+
22
+ private def header
23
+ @out << ("\n#{@gem.fullname}".ljust(28) << "#{@gem.deep_count}".rjust(3))
24
+ @out << hr
25
+ end
26
+
27
+ private def body
28
+ return if @gem.deps.empty?
29
+ @gem.deps.each do |dep|
30
+ @out << dep.to_s(recursive: @recursive)
31
+ end
32
+ @out << "\n"
33
+ end
34
+
35
+ private def hr
36
+ "#{"-" * 30}\n"
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,24 @@
1
+ require "stringio"
2
+
3
+ module Lapidarius
4
+ class UI
5
+ def initialize
6
+ @io = StringIO.new
7
+ end
8
+
9
+ def say(statement)
10
+ @io.puts statement
11
+ end
12
+
13
+ def out
14
+ @io.string.strip
15
+ end
16
+
17
+ def clear!
18
+ @io.reopen("")
19
+ end
20
+
21
+ def terminate_interaction(code = 0)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ module Lapidarius
2
+ VERSION = "1.0.0"
3
+ end
data/tags ADDED
@@ -0,0 +1,33 @@
1
+ !_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
2
+ !_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
3
+ !_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
4
+ !_TAG_PROGRAM_NAME Exuberant Ctags //
5
+ !_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
6
+ !_TAG_PROGRAM_VERSION 5.8 //
7
+ << ./lib/lapidarius/gem.rb /^ def <<(dep)$/;" f class:Lapidarius
8
+ == ./lib/lapidarius/gem.rb /^ def ==(gem)$/;" f class:Lapidarius
9
+ Cutter ./lib/lapidarius/cutter.rb /^ class Cutter$/;" c class:Lapidarius
10
+ Cutter ./spec/mocks.rb /^ class Cutter$/;" c class:Lapidarius
11
+ Env ./lib/lapidarius/env.rb /^ module Env$/;" m class:Lapidarius
12
+ Gem ./lib/lapidarius/gem.rb /^ class Gem$/;" c class:Lapidarius
13
+ KindError ./lib/lapidarius/gem.rb /^ class KindError < ArgumentError; end$/;" c class:Lapidarius.Gem
14
+ Lapidarius ./lib/lapidarius/cutter.rb /^module Lapidarius$/;" m
15
+ Lapidarius ./lib/lapidarius/env.rb /^module Lapidarius$/;" m
16
+ Lapidarius ./lib/lapidarius/gem.rb /^module Lapidarius$/;" m
17
+ Lapidarius ./lib/lapidarius/renderer.rb /^module Lapidarius$/;" m
18
+ Lapidarius ./lib/lapidarius/version.rb /^module Lapidarius$/;" m
19
+ Lapidarius ./spec/mocks.rb /^module Lapidarius$/;" m
20
+ NoEntGemError ./lib/lapidarius/renderer.rb /^ class NoEntGemError< ArgumentError; end$/;" c class:Lapidarius.Renderer
21
+ Renderer ./lib/lapidarius/renderer.rb /^ class Renderer$/;" c class:Lapidarius
22
+ call ./lib/lapidarius/cutter.rb /^ def call(src = cmd, gem = nil)$/;" f class:Lapidarius.Cutter
23
+ call ./lib/lapidarius/renderer.rb /^ def call(io = STDOUT)$/;" f class:Lapidarius.Renderer
24
+ cmd ./spec/mocks.rb /^ def cmd(gem = @gem)$/;" f class:Lapidarius.Cutter
25
+ deps ./lib/lapidarius/gem.rb /^ def deps(env = :all)$/;" f class:Lapidarius
26
+ development? ./lib/lapidarius/gem.rb /^ def development?$/;" f
27
+ factory ./lib/lapidarius/gem.rb /^ def self.factory(name)$/;" F class:Lapidarius.Gem
28
+ initialize ./lib/lapidarius/cutter.rb /^ def initialize(gem:, include_dev: false)$/;" f class:Lapidarius.Cutter
29
+ initialize ./lib/lapidarius/gem.rb /^ def initialize(name:, version:, env: Env::RUNTIME, deps: [])$/;" f class:Lapidarius
30
+ initialize ./lib/lapidarius/renderer.rb /^ def initialize(gem)$/;" f class:Lapidarius.Renderer
31
+ out ./lib/lapidarius/renderer.rb /^ def out$/;" f class:Lapidarius.Renderer
32
+ runtime? ./lib/lapidarius/gem.rb /^ def runtime?$/;" f
33
+ to_s ./lib/lapidarius/gem.rb /^ def to_s$/;" f class:Lapidarius
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lapidarius
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - costajob
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-09-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.12'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.12'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ description:
56
+ email:
57
+ - costajob@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".travis.yml"
64
+ - Gemfile
65
+ - README.md
66
+ - Rakefile
67
+ - bin/console
68
+ - bin/lapidarius
69
+ - bin/setup
70
+ - lapidarius.gemspec
71
+ - lib/lapidarius.rb
72
+ - lib/lapidarius/cli.rb
73
+ - lib/lapidarius/command.rb
74
+ - lib/lapidarius/cutter.rb
75
+ - lib/lapidarius/gem.rb
76
+ - lib/lapidarius/renderer.rb
77
+ - lib/lapidarius/ui.rb
78
+ - lib/lapidarius/version.rb
79
+ - tags
80
+ homepage: https://github.com/costajob/lapidarius
81
+ licenses:
82
+ - MIT
83
+ metadata: {}
84
+ post_install_message:
85
+ rdoc_options: []
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 2.1.8
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubyforge_project:
100
+ rubygems_version: 2.5.1
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: A tiny library to visualize and count gem dependencies recursively
104
+ test_files: []