pry-hack 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/README.md +2 -0
  2. data/examples/method.rb +16 -0
  3. data/lib/pry/hack.rb +225 -0
  4. metadata +126 -0
@@ -0,0 +1,2 @@
1
+ Right now this is as beta as it gets, I'll add more official documents later if demand grows for them.
2
+ As it stands, I need all the help I can get, this is no easy task.
@@ -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
@@ -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: