pry-hack 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 +2 -0
- data/examples/method.rb +16 -0
- data/lib/pry/hack.rb +225 -0
- metadata +126 -0
data/README.md
ADDED
data/examples/method.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require "pry/hack"
|
2
|
+
|
3
|
+
Pry.add_hack(:method, :instance_variable_peek,
|
4
|
+
Pry::Hackage::Hack.new(/^@([A-Za-z_][A-Za-z0-9_]*[A-za-z0-9_\?\!])$/) { replace_with "instance_variable_get(:@#{capture 1})" }
|
5
|
+
)
|
6
|
+
|
7
|
+
Pry.config.hack.enabled = true
|
8
|
+
|
9
|
+
#class Test
|
10
|
+
# def initialize
|
11
|
+
# @hello = :world
|
12
|
+
# end
|
13
|
+
#end
|
14
|
+
#
|
15
|
+
#object = Test.new
|
16
|
+
#puts object.@hello
|
data/lib/pry/hack.rb
ADDED
@@ -0,0 +1,225 @@
|
|
1
|
+
require "pry"
|
2
|
+
require "rubylexer"
|
3
|
+
|
4
|
+
class Pry
|
5
|
+
|
6
|
+
# Configuration block for the plugin
|
7
|
+
# - _s_ A cute way to joke at `hacks', also holds the structures
|
8
|
+
# that contain the {Pry::Hackage::Hack} objects.
|
9
|
+
# - _implications_ Aliases for use in {Pry::Hackage::Hack#initialize}.
|
10
|
+
# - _enabled_ Whether or not the hacks are being used.
|
11
|
+
self.config.hack =
|
12
|
+
OpenStruct.new(
|
13
|
+
:s => OpenStruct.new(
|
14
|
+
:meth => {},
|
15
|
+
:symbol_prefix => {},
|
16
|
+
:modop => {}
|
17
|
+
#:operator => {},
|
18
|
+
#:unary => {},
|
19
|
+
#:identifier => {},
|
20
|
+
#:magic_variable => {},
|
21
|
+
#:unicode => {},
|
22
|
+
),
|
23
|
+
:implications => OpenStruct.new(
|
24
|
+
:method => :meth,
|
25
|
+
:symbol => :symbol_prefix,
|
26
|
+
:% => :modop
|
27
|
+
),
|
28
|
+
:enabled => false
|
29
|
+
)
|
30
|
+
|
31
|
+
# Adds a hack to pry for use in the REPL.
|
32
|
+
#
|
33
|
+
# @param [Symbol] type The type of hack which is being added, this decides the placement
|
34
|
+
# of the object in Pry.config.hack.s
|
35
|
+
#
|
36
|
+
# @param [Object] handle A name to give to the hack, this is needed to remove the hack from
|
37
|
+
# the environment as well.
|
38
|
+
#
|
39
|
+
# @param [Pry::Hackage::Hack] hack The hack that will be added to Pry. See {Pry::Hackage::Hack}
|
40
|
+
#
|
41
|
+
# @return [Pry::Hackage::Hack] The hack that was passed as the last argument of the method.
|
42
|
+
def self.add_hack(type, handle, hack)
|
43
|
+
(eval "self.config.hack.s.#{self.config.hack.implications.send(:method_missing, type)||type}")[handle] = hack
|
44
|
+
return hack
|
45
|
+
end
|
46
|
+
|
47
|
+
# Removes a method from use in the REPL, added by {Pry#add_hack}
|
48
|
+
#
|
49
|
+
# @param [Object] type The name that was assigned to the hack at the time it was added.
|
50
|
+
#
|
51
|
+
# @return [Fixnum] handle The number of hacks with the name given that were removed from
|
52
|
+
# the environment.
|
53
|
+
def self.remove_hack(type, handle)
|
54
|
+
si = self.config.hack.collect(&:size).reduce(0,:+)
|
55
|
+
self.config.hack.each {|hash| hash.delete(handle)}
|
56
|
+
return si - self.config.hack.collect(&:size).reduce(0,:+)
|
57
|
+
end
|
58
|
+
|
59
|
+
# The main module containing the hack code
|
60
|
+
module Hackage
|
61
|
+
|
62
|
+
VERSION = 0.1
|
63
|
+
|
64
|
+
# Regular expressions kept constant for optimization and intended for use to match
|
65
|
+
# patterns that may be used by a hack in the future.
|
66
|
+
REGEX_REGEX = [%r/\A\/(.+?)\/(.+?)*\Z/, %r/%r(.)([^\1\\]|\\.)*\1/]
|
67
|
+
SYMBOL_REGEX = %r/\A\:(.+?)\Z/
|
68
|
+
|
69
|
+
KEYWORDS = %w[BEGIN END alias and begin break case class def defined? do else elsif end ensure for
|
70
|
+
if in module next not or redo rescue retry return super then when while yield]
|
71
|
+
# The base class from which all Hacks extend
|
72
|
+
class Hack
|
73
|
+
|
74
|
+
# Object initialization.
|
75
|
+
#
|
76
|
+
# @param [Regexp] regex The regular expression that matches the hack
|
77
|
+
#
|
78
|
+
# @param [Proc] block The block passed to the method detailing the hack's action.
|
79
|
+
def initialize(regex, &block)
|
80
|
+
@PATTERN = regex
|
81
|
+
@CODE = block
|
82
|
+
define_singleton_method(:capture) do |x|
|
83
|
+
[][x]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Lexical score of a string in relation to the regular expression of the hack.
|
88
|
+
#
|
89
|
+
# @param [String] text The text to be tested for a numerical matching score.
|
90
|
+
#
|
91
|
+
# @return [Fixnum] The score given, or characters matched by the regular expression.
|
92
|
+
def score(text)
|
93
|
+
md = @PATTERN.match(text)
|
94
|
+
return if md.nil?
|
95
|
+
cap = md.captures
|
96
|
+
define_singleton_method(:capture) do |x|
|
97
|
+
cap[x-1]
|
98
|
+
end
|
99
|
+
return cap.join.length
|
100
|
+
end
|
101
|
+
|
102
|
+
def run(where)
|
103
|
+
instance_exec(nil, where, &@CODE)
|
104
|
+
end
|
105
|
+
|
106
|
+
# DSL function that replaces the entire string with the one provided.
|
107
|
+
def replace_with(text)
|
108
|
+
return text
|
109
|
+
end
|
110
|
+
|
111
|
+
# DSL function that acts like String#sub
|
112
|
+
#
|
113
|
+
# @param [String] text The text that will be subject to the sub.
|
114
|
+
#
|
115
|
+
# @param [Hash,String] hash If a hash, you must use the format :with => "text"
|
116
|
+
# and you may also supply :global? => true to apply
|
117
|
+
# a global substitution. See String#gsub
|
118
|
+
#
|
119
|
+
# @return [String] The string post operations.
|
120
|
+
def replace(text, hash)
|
121
|
+
if hash.is_a? Hash
|
122
|
+
if hash[:global?].nil? || hash[:global?]
|
123
|
+
return text.gsub(@PATTERN, hash[:with])
|
124
|
+
else
|
125
|
+
return text.sub(@PATTERN, hash[:with])
|
126
|
+
end
|
127
|
+
else
|
128
|
+
return text.gsub(@PATTERN, hash)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def ignore
|
133
|
+
return nil
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
class ModOpHack < Hack
|
139
|
+
def initialize(char, &block)
|
140
|
+
@CHAR = char
|
141
|
+
@CODE = block
|
142
|
+
define_singleton_method(:capture) do |x|
|
143
|
+
[][x]
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
PAIR_MATCHES = {'[' => ']', '{' => '}', '(' => ')', '<' => '>'}
|
148
|
+
def score(str)
|
149
|
+
str.strip!
|
150
|
+
char = Regexp.escape(str[1])
|
151
|
+
char_to_match = Regexp.escape(PAIR_MATCHES[str[1]]||str[1])
|
152
|
+
@PATTERN = /^#{@CHAR}(#{char})(.*)(#{char_to_match})$/
|
153
|
+
scr = super str
|
154
|
+
define_singleton_method(:delimiter) { Struct.new(:open,:close).new(capture(1), capture(3)) }
|
155
|
+
define_singleton_method(:content) { capture(2) }
|
156
|
+
return scr
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def self.hack_line(str)
|
161
|
+
# A dirty syntax hack used to enable and disable pry-hack when a hack goes
|
162
|
+
# wrong and you are unable to fix it because of a side effect. The syntax is as follows
|
163
|
+
# -*- pry-hack: disable -*-
|
164
|
+
# or to enable
|
165
|
+
# -*- pry-hack: enable -*-
|
166
|
+
if str =~ /#\s*-\*-\s*pry-hack:\s*(disable|enable)\s*-\*-\s*/
|
167
|
+
self.config.hack.enabled = ($1 == "enable") ? true : false
|
168
|
+
end
|
169
|
+
return str unless ::Pry.config.hack.enabled
|
170
|
+
stack = []
|
171
|
+
tstack = []
|
172
|
+
state = nil
|
173
|
+
|
174
|
+
lexer = RubyLexer.new("(pry)", str)
|
175
|
+
tstack = lexer.to_set.to_a[1..-2].select {|x| !(x.is_a? RubyLexer::FileAndLineToken) }
|
176
|
+
tstack.map!(&:to_s)
|
177
|
+
while c = tstack.shift
|
178
|
+
if state.nil?
|
179
|
+
state= case c
|
180
|
+
when '.'
|
181
|
+
# self.config.hack.s.meth
|
182
|
+
:meth
|
183
|
+
when '%'
|
184
|
+
# self.config.hack.s.modop
|
185
|
+
:modop
|
186
|
+
when Hackage::SYMBOL_REGEX
|
187
|
+
# self.config.hack.s.symbol_prefix
|
188
|
+
:symbol_prefix
|
189
|
+
when *Hackage::REGEX_REGEX
|
190
|
+
# self.config.hack.s.regex
|
191
|
+
:regex
|
192
|
+
end
|
193
|
+
stack.push c
|
194
|
+
next
|
195
|
+
else
|
196
|
+
if state == :modop && tstack[0] =~ /[^A-Za-z0-9#]/
|
197
|
+
char = Regexp.escape(tstack[0])
|
198
|
+
char_to_match = Regexp.escape(ModOpHack::PAIR_MATCHES[tstack[0]] || char)
|
199
|
+
c += (tstack.shift + " ") until c =~ /^.#{char}.*#{char_to_match}/
|
200
|
+
end
|
201
|
+
hacks = (self.config.hack.s.send(state).values.sort_by {|x| x.score(c) })
|
202
|
+
if hacks.nil?
|
203
|
+
stack.push c
|
204
|
+
next
|
205
|
+
end
|
206
|
+
hacks.compact!
|
207
|
+
hacks.reject! {|x| x.score(c).nil? }
|
208
|
+
if hacks.any? && stack.last == '%' then stack.pop end # Do this so that you can make sure not to have a double modulo occurance
|
209
|
+
c = (hacks.any?) ? hacks.last.run(binding) : c
|
210
|
+
state = nil
|
211
|
+
stack.push c
|
212
|
+
end
|
213
|
+
end
|
214
|
+
return stack.join
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
alias_method :old_retrieve_line, :retrieve_line
|
219
|
+
|
220
|
+
def retrieve_line(eval_string, *args)
|
221
|
+
old_retrieve_line(eval_string, *args)
|
222
|
+
puts eval_string.sub!(/^.+?$/, Hackage.hack_line(eval_string))
|
223
|
+
end
|
224
|
+
|
225
|
+
end
|
metadata
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pry-hack
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Matthew Carey
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-19 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rubylexer
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: pry
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: minitest
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: ! 'Using a lexical parser, this gem allows you to add hacks to your REPL
|
63
|
+
session allowing you to
|
64
|
+
|
65
|
+
have shortcut syntax. Things such as
|
66
|
+
|
67
|
+
[0] pry(main)> object.@ivar
|
68
|
+
|
69
|
+
=> :im_the_return_of_an_instance_variable
|
70
|
+
|
71
|
+
|
72
|
+
Or
|
73
|
+
|
74
|
+
|
75
|
+
[0] pry(main)> %S{hello symbol world}
|
76
|
+
|
77
|
+
=> [:hello, :symbol, :world]
|
78
|
+
|
79
|
+
|
80
|
+
And even the most desired ruby syntax of all is planned to come, that''s right.
|
81
|
+
Increment and decrement operators.
|
82
|
+
|
83
|
+
|
84
|
+
[0] pry(main)> i++
|
85
|
+
|
86
|
+
=> 1
|
87
|
+
|
88
|
+
[1] pry(main)> i--
|
89
|
+
|
90
|
+
=> 0
|
91
|
+
|
92
|
+
'
|
93
|
+
email: matthew.b.carey@gmail.com
|
94
|
+
executables: []
|
95
|
+
extensions: []
|
96
|
+
extra_rdoc_files: []
|
97
|
+
files:
|
98
|
+
- lib/pry/hack.rb
|
99
|
+
- examples/method.rb
|
100
|
+
- README.md
|
101
|
+
homepage: https://github.com/swarley/pry-hack
|
102
|
+
licenses: []
|
103
|
+
post_install_message:
|
104
|
+
rdoc_options: []
|
105
|
+
require_paths:
|
106
|
+
- lib
|
107
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
108
|
+
none: false
|
109
|
+
requirements:
|
110
|
+
- - ! '>='
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ! '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
requirements: []
|
120
|
+
rubyforge_project:
|
121
|
+
rubygems_version: 1.8.23
|
122
|
+
signing_key:
|
123
|
+
specification_version: 3
|
124
|
+
summary: Change the syntax of your pry session with minimal side effects
|
125
|
+
test_files: []
|
126
|
+
has_rdoc:
|