analyst 0.16.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 25e03d345e3eee79249da960a221c1635de9ded7
4
- data.tar.gz: 939e2a44f33bc42afed68a253be53e4110c0ea21
3
+ metadata.gz: cacc928955bbd8e72446dcf6b20a5cbebc5ec4fc
4
+ data.tar.gz: b4c9cad57b52ba7f6c48f04f9295935cbe918463
5
5
  SHA512:
6
- metadata.gz: 385373476be049c30d9ebccb8ab096496587eae69a85678e420631cf7c1bfb9ce04336b3a316b78e36f0f293186c8967714e3d7fe6d77857e776dfcd60daaa07
7
- data.tar.gz: 8423b501882aab60fac8dfea3b59272d539718731ac6a40e42152c0a512f339a68e8985c31717ecd6d3354d934fb3bd2eb9f4cd710ad53c794a99c91da7cff92
6
+ metadata.gz: 00085874da8ad41948eca83217e3d36e519518a65d197c8fb6b38bb2fbca0ae3fd6a25bb7f3f00337d5400f1d240987a630955a6eefde5419001db7655637360
7
+ data.tar.gz: 238d01df95d83893c687a2bf1e1e9b578dc12218f446137439a997127ec92f16fec87c38b1e1317c4f26a88a563907e5ad92755bdae8e79d96fc41dbb138b0ea
data/analyst.gemspec CHANGED
@@ -32,6 +32,7 @@ Gem::Specification.new do |spec|
32
32
  spec.add_development_dependency "pry"
33
33
  spec.add_development_dependency "byebug"
34
34
  spec.add_development_dependency "awesome_print"
35
+ spec.add_development_dependency "flog"
35
36
 
36
37
  end
37
38
 
@@ -10,11 +10,7 @@ module Analyst
10
10
  end
11
11
 
12
12
  def full_name
13
- scope.nil? ? name : scope.full_name + '::' + name
14
- end
15
-
16
- def scope
17
- @scope ||= process_node(ast.children.first)
13
+ parent.nil? ? name : parent.full_name + '::' + name
18
14
  end
19
15
 
20
16
  private
@@ -24,6 +24,10 @@ module Analyst
24
24
  end
25
25
  end
26
26
 
27
+ def strings
28
+ @strings ||= contents_of_type(Entities::String)
29
+ end
30
+
27
31
  def modules
28
32
  @modules ||= begin
29
33
  nested_modules = top_level_modules.map(&:modules).flatten
@@ -70,6 +74,10 @@ module Analyst
70
74
  @conditionals ||= contents_of_type(Entities::Conditional)
71
75
  end
72
76
 
77
+ def hashes
78
+ @hashes ||= contents_of_type(Entities::Hash)
79
+ end
80
+
73
81
  def location
74
82
  "#{file_path}:#{line_number}"
75
83
  end
@@ -25,6 +25,12 @@ module Analyst
25
25
  hash
26
26
  end
27
27
  end
28
+
29
+ private
30
+
31
+ def contents
32
+ pairs
33
+ end
28
34
  end
29
35
  end
30
36
  end
@@ -19,18 +19,10 @@ module Analyst
19
19
  end
20
20
  end
21
21
 
22
- def constants
23
- if target.is_a? Analyst::Entities::Constant
24
- super << target
25
- else
26
- super
27
- end
28
- end
29
-
30
22
  private
31
23
 
32
24
  def contents
33
- arguments
25
+ (arguments + [target]).compact
34
26
  end
35
27
 
36
28
  def target_node
@@ -38,7 +30,7 @@ module Analyst
38
30
  end
39
31
 
40
32
  def target
41
- process_node(target_node)
33
+ @target ||= process_node(target_node)
42
34
  end
43
35
 
44
36
  def name_node
@@ -6,11 +6,17 @@ module Analyst
6
6
  handles_node :pair
7
7
 
8
8
  def key
9
- process_node(ast.children[0])
9
+ @key ||= process_node(ast.children[0])
10
10
  end
11
11
 
12
12
  def value
13
- process_node(ast.children[1])
13
+ @value ||= process_node(ast.children[1])
14
+ end
15
+
16
+ private
17
+
18
+ def contents
19
+ [key, value]
14
20
  end
15
21
  end
16
22
  end
@@ -7,7 +7,7 @@ module Analyst
7
7
  extend Forwardable
8
8
 
9
9
  def_delegators :root, :classes, :top_level_classes, :constants,
10
- :methods
10
+ :methods, :method_calls, :hashes
11
11
 
12
12
  def self.for_files(*path_to_files)
13
13
  file_paths = path_to_files.map do |path|
@@ -1,3 +1,3 @@
1
1
  module Analyst
2
- VERSION = "0.16.1"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Analyst::Entities::ClassMethod do
4
+
5
+ let(:code) {<<-CODE
6
+ class DefaultCarrier
7
+ def self.register(carrier)
8
+ CarrierRegistry.add(carrier)
9
+ end
10
+ end
11
+ CODE
12
+ }
13
+ let(:parser) { Analyst.for_source(code) }
14
+ let(:klass) { parser.classes.first }
15
+ let(:method) { klass.cmethods.first }
16
+
17
+ describe "#name" do
18
+ it "returns its short name" do
19
+ expect(method.name).to eq("register")
20
+ end
21
+ end
22
+
23
+ describe "#fulL_name" do
24
+ it "returns its fully qualified name" do
25
+ expect(method.full_name).to eq("DefaultCarrier::register")
26
+ end
27
+ end
28
+
29
+ end
@@ -5,6 +5,7 @@ describe Analyst::Entities::Class do
5
5
  let(:parser) { Analyst.for_file("./spec/fixtures/music.rb") }
6
6
  let(:artist) { parser.classes.detect { |klass| klass.full_name == "Artist" } }
7
7
  let(:singer) { parser.classes.detect { |klass| klass.full_name == "Singer" } }
8
+ let(:amp) { parser.classes.detect { |klass| klass.full_name == "Performances::Equipment::Amp" }}
8
9
 
9
10
  describe "#method_calls" do
10
11
  it "lists all method invocations within a class definition" do
@@ -27,4 +28,11 @@ describe Analyst::Entities::Class do
27
28
  end
28
29
  end
29
30
 
31
+ describe "#constants" do
32
+ it "returns a list of constants" do
33
+ constants = amp.constants.map(&:name)
34
+ expect(constants).to match_array ["Interfaces::Basic", "Performances::Equipment::Microphone", "Performances::Equipment::MicStand"]
35
+ end
36
+ end
37
+
30
38
  end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe Analyst::Entities::ConstantAssignment do
4
+
5
+ let(:code) {<<-CODE
6
+ class Carrier
7
+ OBSTACLES = [:rain, :sleet, :snow]
8
+ def deliver(mail)
9
+ delivery = Delivery.new(mail)
10
+ delivery.deliver!
11
+ end
12
+ end
13
+ CODE
14
+ }
15
+ let(:parser) { Analyst.for_source(code) }
16
+ let(:klass) { parser.classes.first }
17
+ let(:constant_assignment) { klass.constant_assignments.first }
18
+
19
+ describe "#name" do
20
+ it "returns the short name of a constant" do
21
+ expect(constant_assignment.name).to eq("OBSTACLES")
22
+ end
23
+ end
24
+
25
+ describe "#full_name" do
26
+ it "returns the full name of a constant" do
27
+ expect(constant_assignment.full_name).to eq("Carrier::OBSTACLES")
28
+ end
29
+ end
30
+
31
+ end
@@ -46,6 +46,12 @@ describe Analyst::Entities::Entity do
46
46
  found = Analyst.for_source(code).constants.map(&:full_name)
47
47
  expect(found).to match_array %w[A B C]
48
48
  end
49
+
50
+ it "finds constants inside of interpolated strings" do
51
+ code = 'str = "Today, scientists classify Pluto as a #{Pluto.wtfru?}"'
52
+ found = Analyst.for_source(code).constants.map(&:name)
53
+ expect(found).to match_array %w[Pluto]
54
+ end
49
55
  end
50
56
 
51
57
  describe "#conditionals" do
@@ -115,4 +121,20 @@ end
115
121
  end
116
122
  end
117
123
 
124
+ describe "#method_calls" do
125
+ it "detects method calls" do
126
+ code = 'do_that_thang'
127
+ found = Analyst.for_source(code).method_calls.map(&:name)
128
+ expect(found).to match_array %w[do_that_thang]
129
+ end
130
+
131
+ it "detects calls inside calls" do
132
+ code = 'do_that_thang(with_this_stuff)'
133
+ do_that_thang = Analyst.for_source(code).method_calls.first
134
+ found = do_that_thang.method_calls.map(&:name)
135
+ expect(found).to match_array %w[with_this_stuff]
136
+ end
137
+
138
+ end
139
+
118
140
  end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ describe Analyst::Entities::Hash do
4
+
5
+ let(:code) {<<-CODE
6
+ class Postmark
7
+ attr_accessor :date, :origin_city
8
+ def to_hash
9
+ {
10
+ date: self.date,
11
+ sent_from: self.origin_city
12
+ }
13
+ end
14
+ end
15
+ CODE
16
+ }
17
+ let(:parser) { Analyst.for_source(code) }
18
+ let(:klass) { parser.classes.first }
19
+ let(:methods) { klass.imethods }
20
+
21
+ describe "#pairs" do
22
+ let(:pairs) { methods.map(&:hashes).flatten.first.pairs }
23
+
24
+ it "extracts key/value pairs" do
25
+ expect(pairs.map(&:class)).to eq(
26
+ [Analyst::Entities::Pair, Analyst::Entities::Pair]
27
+ )
28
+ end
29
+ end
30
+
31
+ describe "#to_hash" do
32
+ let(:hash_entity) { methods.map(&:hashes).flatten.first }
33
+ it "returns a hash with appropriate keys" do
34
+ expect(hash_entity.to_hash.keys).to eq(
35
+ [:date, :sent_from]
36
+ )
37
+ end
38
+ it "returns a hash with appropriate values" do
39
+ expect(hash_entity.to_hash.values.map(&:class)).to eq(
40
+ [Analyst::Entities::MethodCall, Analyst::Entities::MethodCall]
41
+ )
42
+ end
43
+ end
44
+
45
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Analyst::Entities::InstanceMethod do
4
+
5
+ let(:code) {<<-CODE
6
+ class DefaultCarrier
7
+ def initialize
8
+ @foo = "bar"
9
+ end
10
+ end
11
+ CODE
12
+ }
13
+ let(:parser) { Analyst.for_source(code) }
14
+ let(:klass) { parser.classes.first }
15
+ let(:method) { klass.imethods.first }
16
+
17
+ describe "#name" do
18
+ it "returns its short name" do
19
+ expect(method.name).to eq("initialize")
20
+ end
21
+ end
22
+
23
+ describe "#fulL_name" do
24
+ it "returns its fully qualified name" do
25
+ expect(method.full_name).to eq("DefaultCarrier#initialize")
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Analyst::Entities::MethodCall do
4
+
5
+ describe "#constants" do
6
+ let(:code) { "Universe.spawn(Star, into: Galaxy.named('Milky Way'))" }
7
+ let(:method_call) { Analyst.for_source(code).method_calls.first }
8
+
9
+ it "lists constant targets and arguments" do
10
+ found = method_call.constants.map(&:name)
11
+ expect(found).to match_array %w[Universe Star Galaxy]
12
+ end
13
+ end
14
+
15
+ describe "#arguments" do
16
+ it "lists arguments" do
17
+ code = "fn(:one, 'two', three)"
18
+ args = Analyst.for_source(code).method_calls.first.arguments
19
+
20
+ expect(args[0].value).to be :one
21
+ expect(args[1].value).to eq 'two'
22
+ expect(args[2].class).to eq Analyst::Entities::MethodCall
23
+ expect(args[2].name).to eq 'three'
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe Analyst::Entities::SingletonClass do
4
+
5
+ let(:code) {<<-CODE
6
+ class FriendlyStaff
7
+ class << self
8
+ def greet_customers
9
+ "Hello customers!"
10
+ end
11
+ end
12
+ end
13
+ CODE
14
+ }
15
+ let(:parser) { Analyst.for_source(code) }
16
+ let(:klass) { parser.classes.first }
17
+ let(:singleton) { klass.singleton_class_blocks.first }
18
+
19
+ describe "#name" do
20
+ it "returns its short name" do
21
+ expect(singleton.name).to eq("FriendlyStaff!SINGLETON")
22
+ end
23
+ end
24
+
25
+ describe "#fulL_name" do
26
+ it "returns its fully qualified name" do
27
+ expect(singleton.full_name).to eq("FriendlyStaff!SINGLETON")
28
+ end
29
+ end
30
+
31
+ describe "#smethods" do
32
+ it "returns its singleton methods" do
33
+ expect(singleton.smethods.first.name).to eq("greet_customers")
34
+ end
35
+ end
36
+
37
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Analyst::Entities::String do
4
+
5
+ let(:code) {<<-CODE
6
+ class DefaultCarrier
7
+ def initialize
8
+ "USPS"
9
+ end
10
+ end
11
+ CODE
12
+ }
13
+ let(:parser) { Analyst.for_source(code) }
14
+ let(:klass) { parser.classes.first }
15
+ let(:string) { klass.imethods.first.strings.first }
16
+
17
+ describe "#value" do
18
+ it "returns the value of the string" do
19
+ expect(string.value).to eq("USPS")
20
+ end
21
+ end
22
+
23
+ end
@@ -49,7 +49,6 @@ class Singer < Artist
49
49
  end
50
50
 
51
51
  class Song
52
-
53
52
  def initialize(popularity)
54
53
  @popularity = popularity
55
54
  end
@@ -58,14 +57,12 @@ end
58
57
  module Instruments
59
58
 
60
59
  class Stringed
61
-
62
60
  def initialize(num_strings)
63
61
  @num_strings = num_strings
64
62
  end
65
63
  end
66
64
 
67
65
  class Guitar < Stringed
68
-
69
66
  def initialize(sound)
70
67
  super(6)
71
68
  @sound = sound
@@ -76,11 +73,22 @@ end
76
73
 
77
74
  module Performances
78
75
  module Equipment
76
+
79
77
  class Amp
78
+ include Interfaces::Basic
79
+ def self.companion_gear(type)
80
+ [
81
+ Performances::Equipment::Microphone.new("mic_1").on,
82
+ Performances::Equipment::MicStand.new("mic_1_stand")
83
+ ]
84
+ end
80
85
  end
81
86
 
82
87
  class Microphone
83
88
  end
89
+
90
+ class MicStand
91
+ end
92
+
84
93
  end
85
94
  end
86
-
data/spec/parser_spec.rb CHANGED
@@ -18,7 +18,9 @@ describe "Parser" do
18
18
  all_classes = %w[Artist Singer Song
19
19
  Instruments::Stringed Instruments::Guitar
20
20
  Performances::Equipment::Amp
21
- Performances::Equipment::Microphone]
21
+ Performances::Equipment::Microphone
22
+ Performances::Equipment::MicStand
23
+ ]
22
24
 
23
25
  class_names = parser.classes.map(&:full_name)
24
26
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: analyst
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Coraline Ada Ehmke
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-11-10 00:00:00.000000000 Z
12
+ date: 2014-11-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: haml
@@ -193,6 +193,20 @@ dependencies:
193
193
  - - ">="
194
194
  - !ruby/object:Gem::Version
195
195
  version: '0'
196
+ - !ruby/object:Gem::Dependency
197
+ name: flog
198
+ requirement: !ruby/object:Gem::Requirement
199
+ requirements:
200
+ - - ">="
201
+ - !ruby/object:Gem::Version
202
+ version: '0'
203
+ type: :development
204
+ prerelease: false
205
+ version_requirements: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - ">="
208
+ - !ruby/object:Gem::Version
209
+ version: '0'
196
210
  description: A nice API for interacting with parsed Ruby source code.
197
211
  email:
198
212
  - coraline@idolhands.com
@@ -235,11 +249,17 @@ files:
235
249
  - lib/analyst/parser.rb
236
250
  - lib/analyst/processor.rb
237
251
  - lib/analyst/version.rb
238
- - spec/class_spec.rb
239
- - spec/constant_spec.rb
240
- - spec/entity_spec.rb
252
+ - spec/entities/class_method_spec.rb
253
+ - spec/entities/class_spec.rb
254
+ - spec/entities/constant_assignment_spec.rb
255
+ - spec/entities/constant_spec.rb
256
+ - spec/entities/entity_spec.rb
257
+ - spec/entities/hash_spec.rb
258
+ - spec/entities/instance_method_spec.rb
259
+ - spec/entities/method_call_spec.rb
260
+ - spec/entities/singleton_class_spec.rb
261
+ - spec/entities/string_spec.rb
241
262
  - spec/fixtures/music.rb
242
- - spec/method_spec.rb
243
263
  - spec/parser_spec.rb
244
264
  - spec/spec_helper.rb
245
265
  homepage: ''
@@ -267,11 +287,17 @@ signing_key:
267
287
  specification_version: 4
268
288
  summary: A nice API for interacting with parsed Ruby source code.
269
289
  test_files:
270
- - spec/class_spec.rb
271
- - spec/constant_spec.rb
272
- - spec/entity_spec.rb
290
+ - spec/entities/class_method_spec.rb
291
+ - spec/entities/class_spec.rb
292
+ - spec/entities/constant_assignment_spec.rb
293
+ - spec/entities/constant_spec.rb
294
+ - spec/entities/entity_spec.rb
295
+ - spec/entities/hash_spec.rb
296
+ - spec/entities/instance_method_spec.rb
297
+ - spec/entities/method_call_spec.rb
298
+ - spec/entities/singleton_class_spec.rb
299
+ - spec/entities/string_spec.rb
273
300
  - spec/fixtures/music.rb
274
- - spec/method_spec.rb
275
301
  - spec/parser_spec.rb
276
302
  - spec/spec_helper.rb
277
303
  has_rdoc:
data/spec/method_spec.rb DELETED
@@ -1,9 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Analyst::Entities::InstanceMethod do
4
-
5
- it "has specs" do
6
- expect(false).to be_truthy
7
- end
8
-
9
- end