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.
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: