puncsig 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,4 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new
4
+ task :default => :test
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,12 @@
1
+ require 'puncsig'
2
+ require 'rails'
3
+
4
+ module Puncsig
5
+ class Railtie < Rails::Railtie
6
+ railtie_name :puncsig
7
+
8
+ rake_tasks do
9
+ load "tasks/puncsig.rake"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ module Puncsig
2
+ VERSION = "0.0.1"
3
+ end
@@ -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: []