puncsig 0.0.1
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.
- data/README.md +134 -0
- data/Rakefile +4 -0
- data/lib/puncsig.rb +78 -0
- data/lib/puncsig/railtie.rb +12 -0
- data/lib/puncsig/version.rb +3 -0
- data/lib/tasks/puncsig.rake +51 -0
- data/puncsig.gemspec +35 -0
- metadata +54 -0
data/README.md
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
# puncsig: Punctuation Signatures
|
2
|
+
|
3
|
+
## What Is This?
|
4
|
+
|
5
|
+
Inspired by Ward Cunningham's [Signature Survey: A Method for Browsing
|
6
|
+
Unfamiliar Code](http://c2.com/doc/SignatureSurvey/), "puncsig" is
|
7
|
+
short for "punctuation signature": it parses ruby code, and shows you
|
8
|
+
just the punctuation from the methods. It gives you a rough idea of
|
9
|
+
the length of each method, and helps you spot similar methods.
|
10
|
+
|
11
|
+
## Install
|
12
|
+
|
13
|
+
In your Gemfile:
|
14
|
+
|
15
|
+
```
|
16
|
+
gem 'puncsig'
|
17
|
+
```
|
18
|
+
|
19
|
+
...or on your command line:
|
20
|
+
|
21
|
+
```
|
22
|
+
$ gem install puncsig
|
23
|
+
```
|
24
|
+
|
25
|
+
You know, the basics.
|
26
|
+
|
27
|
+
## Use It
|
28
|
+
|
29
|
+
In your rails app:
|
30
|
+
|
31
|
+
```
|
32
|
+
$ bundle exec rake -T puncsig
|
33
|
+
rake puncsig:all # Run puncsig on the whole app
|
34
|
+
rake puncsig:controllers # Run puncsig on just the controllers
|
35
|
+
rake puncsig:helpers # Run puncsig on just the helpers
|
36
|
+
rake puncsig:lib # Run puncsig on just the files in lib
|
37
|
+
rake puncsig:models # Run puncsig on just the models
|
38
|
+
```
|
39
|
+
|
40
|
+
TODO In a normal ruby app. It's not quite here yet, I want to separate
|
41
|
+
it out a bit more. Coming soon, promise!
|
42
|
+
|
43
|
+
## Example: rstat.us
|
44
|
+
|
45
|
+
Just for fun, let's take a look at the [rstat.us
|
46
|
+
source](https://github.com/hotsh/rstat.us). I chose rstat.us strictly
|
47
|
+
because a) it was open-source ruby, and b) it cleanly installed, so
|
48
|
+
whatever puncsig says about the source, that's a great start - and I
|
49
|
+
gave up on several others, because I couldn't get them installed
|
50
|
+
easily. We _all_ have code that needs some love, and I have much love
|
51
|
+
for the people behind rstat.us.
|
52
|
+
|
53
|
+
```
|
54
|
+
$ be rake puncsig:models
|
55
|
+
|
56
|
+
[...]
|
57
|
+
|
58
|
+
app/models/salmon_author.rb
|
59
|
+
author_attributes: {:=>,:=>,:=>,:=>,:=>,:=>,:=>}==().==.==.==.&&==.&&==.&&==.&&==.&&==.
|
60
|
+
avatar_url: @..{||..==}..
|
61
|
+
email: =@.==
|
62
|
+
initialize: ()@=
|
63
|
+
bio: @..
|
64
|
+
name: @..
|
65
|
+
uri: @.
|
66
|
+
username: @.
|
67
|
+
|
68
|
+
[...]
|
69
|
+
|
70
|
+
app/models/user.rb
|
71
|
+
no_malformed_username: (=~/[@!#$\%&()*,^~{}|`=:;\\\/\[\]\?]/).?&&(=~/^[.]/).?&&(=~/[.]$/).?&&(=~/[.]{,}/).?.(:,.,,.)
|
72
|
+
send_mention_notification: (,)=.:=>=.:=>=://#{.}/=::.(.())=..=.(..)=::.(.,.)=.(.,,{-=>/-+})
|
73
|
+
edit_user_profile: ()[:].?[:].?[:]==[:].=[:]..=.==[:].=[:]..=[:].=[:].=[:].=[:]...
|
74
|
+
following_url?: ()=.(:=>).?.?(://#{.}/)=[/\/\/(.+)$/,]=[.(:=>)].?!(&).?!
|
75
|
+
send_unfollow_notification: ()=.:=>=::.(.,..)=..=.(..)=::.(.,.)=.(.,,{-=>/-+})
|
76
|
+
send_follow_notification: ()=.:=>=::.(.,..)=..=.(..)=::.(.,.)=.(.,,{-=>/-+})
|
77
|
+
|
78
|
+
[...]
|
79
|
+
```
|
80
|
+
|
81
|
+
Look at these two signatures from app/models/discussion_list.rb:
|
82
|
+
|
83
|
+
```
|
84
|
+
send_unfollow_notification: ()=.:=>=::.(.,..)=..=.(..)=::.(.,.)=.(.,,{-=>/-+})
|
85
|
+
send_follow_notification: ()=.:=>=::.(.,..)=..=.(..)=::.(.,.)=.(.,,{-=>/-+})
|
86
|
+
```
|
87
|
+
|
88
|
+
There's clearly something similar about them. Here's the source:
|
89
|
+
|
90
|
+
```
|
91
|
+
# Send Salmon notification so that the remote user
|
92
|
+
# knows this user is following them
|
93
|
+
def send_follow_notification(to_feed_id)
|
94
|
+
f = Feed.first :id => to_feed_id
|
95
|
+
|
96
|
+
salmon = OStatus::Salmon.from_follow(author.to_atom, f.author.to_atom)
|
97
|
+
|
98
|
+
envelope = salmon.to_xml self.to_rsa_keypair
|
99
|
+
|
100
|
+
# Send envelope to Author's Salmon endpoint
|
101
|
+
uri = URI.parse(f.author.salmon_url)
|
102
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
103
|
+
res = http.post(uri.path, envelope, {"Content-Type" => "application/magic-envelope+xml"})
|
104
|
+
end
|
105
|
+
|
106
|
+
# Send Salmon notification so that the remote user
|
107
|
+
# knows this user has stopped following them
|
108
|
+
def send_unfollow_notification(to_feed_id)
|
109
|
+
f = Feed.first :id => to_feed_id
|
110
|
+
|
111
|
+
salmon = OStatus::Salmon.from_unfollow(author.to_atom, f.author.to_atom)
|
112
|
+
|
113
|
+
envelope = salmon.to_xml self.to_rsa_keypair
|
114
|
+
|
115
|
+
# Send envelope to Author's Salmon endpoint
|
116
|
+
uri = URI.parse(f.author.salmon_url)
|
117
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
118
|
+
res = http.post(uri.path, envelope, {"Content-Type" => "application/magic-envelope+xml"})
|
119
|
+
end
|
120
|
+
```
|
121
|
+
|
122
|
+
Definitely some kind of duplication there, and these methods aren't
|
123
|
+
right next to each other in the source.
|
124
|
+
|
125
|
+
And it helps us find really long methods, like these bad boys:
|
126
|
+
|
127
|
+
```
|
128
|
+
app/models/update.rb
|
129
|
+
generate_html: =.().!(/([]?:\/\/\+[---\/}])/,<=\\>\\</>).!()||$=.(:=>/^#{$}$/,:=>/^#{$}$/)=..?(/)=://#{.}#{}#{$}<=#{}>@#{$}@#{$}</>$=.(:=>/^#{$}$/)=..?(/)=://#{.}#{}#{$}<=#{}>@#{$}</>.!(/(^|\+)#(\+)/)||#{$}<=/?=%#{$}>##{$}</>.=
|
130
|
+
```
|
131
|
+
|
132
|
+
## TODOS
|
133
|
+
|
134
|
+
* break it up & test it a bit.
|
data/Rakefile
ADDED
data/lib/puncsig.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
module Puncsig
|
2
|
+
|
3
|
+
class FileReport
|
4
|
+
attr_reader :filename
|
5
|
+
|
6
|
+
def initialize(filename, method_sigs)
|
7
|
+
@filename = filename
|
8
|
+
@method_sigs = method_sigs
|
9
|
+
end
|
10
|
+
|
11
|
+
def method_names
|
12
|
+
@method_sigs.keys
|
13
|
+
end
|
14
|
+
|
15
|
+
# Not sure this is how it'll end up...
|
16
|
+
def method_sigs
|
17
|
+
@method_sigs
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Parser
|
22
|
+
def parse(filename)
|
23
|
+
src = src(filename)
|
24
|
+
methods = methods(src)
|
25
|
+
method_sigs = Hash[*methods.map { |name, src| [name, puncsig(src)] }.flatten]
|
26
|
+
FileReport.new(filename, method_sigs)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def src(path)
|
32
|
+
File.read(path).gsub(/^\s*#.*$/, '')
|
33
|
+
end
|
34
|
+
|
35
|
+
# Note: for models, this ignores stuff like named_scopes, etc. That's ok for now, and maybe ok for later.
|
36
|
+
def methods(src)
|
37
|
+
|
38
|
+
# TODO This leaves out methods like [], <<, etc...maybe just check for first non-space?
|
39
|
+
method_sigs = /def\s+[a-z_!?.]+/
|
40
|
+
method_names = src.scan(method_sigs).map { |sig| sig.sub(/^def /, '') }
|
41
|
+
|
42
|
+
bodies = src.split(method_sigs)[1..-1] # strip off first chunk, the class beginning
|
43
|
+
|
44
|
+
method_names.zip(bodies)
|
45
|
+
end
|
46
|
+
|
47
|
+
def puncsig(src)
|
48
|
+
src.gsub(/[a-z0-9'"_\s]/i, '')
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
class Report
|
54
|
+
|
55
|
+
def initialize(*filename_methods)
|
56
|
+
@filenames = filename_methods.flatten
|
57
|
+
end
|
58
|
+
|
59
|
+
def run
|
60
|
+
parser = Parser.new
|
61
|
+
|
62
|
+
@filenames.each do |filename|
|
63
|
+
|
64
|
+
file_report = parser.parse(filename)
|
65
|
+
len = file_report.method_names.map(&:size).max
|
66
|
+
|
67
|
+
puts file_report.filename
|
68
|
+
file_report.method_sigs.sort_by { |n, s| -s.size }.each do |name, sig|
|
69
|
+
print "#{name}:".ljust(len + 3)
|
70
|
+
puts sig
|
71
|
+
end
|
72
|
+
puts
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
require 'puncsig/railtie' if defined?(Rails)
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'puncsig'
|
2
|
+
|
3
|
+
namespace :puncsig do
|
4
|
+
desc "Run puncsig on the whole app"
|
5
|
+
task :all do
|
6
|
+
Puncsig::Report.new(controllers + models + helpers + lib).run
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "Run puncsig on just the models"
|
10
|
+
task :models do
|
11
|
+
Puncsig::Report.new(models).run
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "Run puncsig on just the controllers"
|
15
|
+
task :controllers do
|
16
|
+
Puncsig::Report.new(controllers).run
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Run puncsig on just the helpers"
|
20
|
+
task :helpers do
|
21
|
+
Puncsig::Report.new(helpers).run
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "Run puncsig on just the files in lib"
|
25
|
+
task :lib do
|
26
|
+
Puncsig::Report.new(lib).run
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
def controllers
|
32
|
+
all_under("app/controllers")
|
33
|
+
end
|
34
|
+
|
35
|
+
def models
|
36
|
+
all_under("app/models")
|
37
|
+
end
|
38
|
+
|
39
|
+
def helpers
|
40
|
+
all_under("app/helpers")
|
41
|
+
end
|
42
|
+
|
43
|
+
def lib
|
44
|
+
all_under("lib")
|
45
|
+
end
|
46
|
+
|
47
|
+
def all_under(dir)
|
48
|
+
Dir.glob(File.join(dir, '**/*.rb'))
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
data/puncsig.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require './lib/puncsig/version'
|
2
|
+
|
3
|
+
spec = Gem::Specification.new do |s|
|
4
|
+
s.name = 'puncsig'
|
5
|
+
s.version = Puncsig::VERSION
|
6
|
+
|
7
|
+
s.summary = %{
|
8
|
+
PuncSig: Punctuation Signatures for your ruby methods
|
9
|
+
}.strip.gsub(/\s+/, ' ')
|
10
|
+
|
11
|
+
s.description = %{
|
12
|
+
|
13
|
+
A method's punctuation signature is its source, minus all letters,
|
14
|
+
numbers, and whitespace. It can help you find similar methods,
|
15
|
+
find long methods, and see how your methods are balanced.
|
16
|
+
|
17
|
+
PuncSig parses your ruby classes and prints a report on your
|
18
|
+
classes' punctuation signatures.
|
19
|
+
|
20
|
+
}.strip.gsub(/\s+/, ' ')
|
21
|
+
|
22
|
+
s.files = Dir['lib/**/*.rb'] + Dir['test/**/*.rb'] + %w[
|
23
|
+
README.md
|
24
|
+
Rakefile
|
25
|
+
lib/tasks/puncsig.rake
|
26
|
+
puncsig.gemspec
|
27
|
+
]
|
28
|
+
|
29
|
+
s.require_path = 'lib'
|
30
|
+
s.required_ruby_version = ">= 1.8.7"
|
31
|
+
|
32
|
+
s.author = "Dan Bernier"
|
33
|
+
s.email = "danbernier@gmail.com"
|
34
|
+
s.homepage = "https://github.com/danbernier/puncsig"
|
35
|
+
end
|
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: puncsig
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Dan Bernier
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-07-31 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: A method's punctuation signature is its source, minus all letters, numbers,
|
15
|
+
and whitespace. It can help you find similar methods, find long methods, and see
|
16
|
+
how your methods are balanced. PuncSig parses your ruby classes and prints a report
|
17
|
+
on your classes' punctuation signatures.
|
18
|
+
email: danbernier@gmail.com
|
19
|
+
executables: []
|
20
|
+
extensions: []
|
21
|
+
extra_rdoc_files: []
|
22
|
+
files:
|
23
|
+
- lib/puncsig/railtie.rb
|
24
|
+
- lib/puncsig/version.rb
|
25
|
+
- lib/puncsig.rb
|
26
|
+
- README.md
|
27
|
+
- Rakefile
|
28
|
+
- lib/tasks/puncsig.rake
|
29
|
+
- puncsig.gemspec
|
30
|
+
homepage: https://github.com/danbernier/puncsig
|
31
|
+
licenses: []
|
32
|
+
post_install_message:
|
33
|
+
rdoc_options: []
|
34
|
+
require_paths:
|
35
|
+
- lib
|
36
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
38
|
+
requirements:
|
39
|
+
- - ! '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 1.8.7
|
42
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
requirements: []
|
49
|
+
rubyforge_project:
|
50
|
+
rubygems_version: 1.8.10
|
51
|
+
signing_key:
|
52
|
+
specification_version: 3
|
53
|
+
summary: ! 'PuncSig: Punctuation Signatures for your ruby methods'
|
54
|
+
test_files: []
|