Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 2.0.0 #5

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changelog

## v 2.0.0

API changes:
1. change macro names to `macro-start`, `macro-stop`, `macro-save`, more easy to remember.
2. Remove highline dependency, don't ask macro name when run `macro-stop`, instead, need provide macro name when run `macro-start`
3. `macro-save` save macro to ~/.pry-macro instead of ~/.pryrc, still will autoload all macros too.
4. when recording macro, will skip `edit` command, this will permit you use your favorited editor to edit macro!

Bugfix:
1. Fix for work with newest Pry.

## v 1.0.1 - Bug fix

Removed dependency on pry-plus
Expand Down Expand Up @@ -31,4 +42,3 @@ Added options
## v 0.0.1

Initial release

1 change: 1 addition & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Copyright (c) 2014 Brandon Weaver
Copyright (c) 2019 Billy Zheng

MIT License

Expand Down
18 changes: 11 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# PryMacro

2.0 is released!, please see [CHANGELOG](https://github.com/zw963/pry-macro)

Record command line actions for replaying.

## How is this different from play and history?
Expand All @@ -9,10 +11,10 @@ later, as well as use pry commands.

## Basic Usage

Start recording:
Start recording, you need provide a macro name.

```ruby
[1] pry(main)> record-macro
[1] pry(main)> macro-start testing
[2] pry(main)> 1
=> 1
[3] pry(main)> 'foo'
Expand All @@ -22,11 +24,10 @@ self.methods: inspect to_s
locals: _ __ _dir_ _ex_ _file_ _in_ _out_ _pry_
```

Stop the recording and name it:
Stop the recording:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: s/record/recording


```ruby
[5] pry(main)> stop-macro
Macro Name: testing
[5] pry(main)> macro-stop
```

Run it like any other command:
Expand All @@ -39,15 +40,16 @@ self.methods: inspect to_s
locals: _ __ _dir_ _ex_ _file_ _in_ _out_ _pry_
```

Like it? You can save it and have it automatically append to your PryRC:
Like it? You can save it to ~/.pry-macro, and will load automatically when next run pry!

```ruby
[10] pry(main)> save-macro testing
[10] pry(main)> macro-save testing
```

...and here it is, nice and formatted:

```ruby
╰─ $ cat ~/.pry-macro
Pry::Commands.block_command 'testing', 'no description' do
_pry_.input = StringIO.new(
<<-MACRO.gsub(/^ {4,6}/, '')
Expand All @@ -61,6 +63,8 @@ end

## More Advanced Usage

When recording macro, you can run `edit` command in any time to write macro use you favorited editor!

We're working on getting the Wiki up to date to cover more advanced usage.

## Why?
Expand Down
161 changes: 82 additions & 79 deletions lib/pry-macro.rb
Original file line number Diff line number Diff line change
@@ -1,76 +1,78 @@
require "pry-macro/version"
require 'highline/import'
require 'pry'

module PryMacro
MacroString = Struct.new(:name, :command)

Commands = Pry::CommandSet.new do
create_command 'record-macro', 'Starts a recording session' do
banner <<-BANNER
Usage: record-macro
Pry::Commands.create_command 'macro-start' do
description 'Starts recording a macro.'

Starts recording a macro.
BANNER
def options(opts)
opts.banner <<-BANNER
Usage: #{command_name}111 name [-d desc], [-v]
zw963 marked this conversation as resolved.
Show resolved Hide resolved

Starts recording a macro, have to provide a macro name to be execute as command later.
Descriptions may be provided, but will default to 'no description'.
BANNER
zw963 marked this conversation as resolved.
Show resolved Hide resolved
opts.on :d, :desc, "Description of the macro.",
optional_argument: true, as: String
opts.on :v, :verbose, "Echoes back the macro definition."
end

def process
# Define a few extra ivars on the current pry session so we can persist some state to use
unless _pry_.instance_variable_defined?(:@record_stack)
_pry_.instance_variable_set(:@record_stack, [])
_pry_.instance_variable_set(:@macro_strings, [])
_pry_.class.class_eval 'attr_accessor :record_stack, :macro_strings'
end
def process
raise Pry::CommandError, "The command '#{command_name}' must specify macro name!" if args.empty?

# By using a stack we can potentially have multiple sessions going. Use at your own peril though...
_pry_.record_stack << Pry.history.session_line_count
# Define a few extra ivars on the current pry session so we can persist some state to use
unless _pry_.instance_variable_defined?(:@record_stack)
_pry_.class.class_eval 'attr_accessor :record_stack, :macro_strings, :pry_macro_options', __FILE__, __LINE__
_pry_.record_stack = []
_pry_.macro_strings = []
_pry_.pry_macro_options = {name: args.first, desc: opts[:desc], verbose: opts[:verbose]}
end

# By using a stack we can potentially have multiple sessions going. Use at your own peril though...
_pry_.record_stack << Pry.history.session_line_count
end
end

create_command 'stop-macro', 'Stops a recording session, and saves a macro' do
banner <<-BANNER
Usage: stop-macro [-n name] [-d desc]
Pry.commands.create_command 'macro-stop' do
description 'Stops recording macro.'

Stops recording a macro, loads the command, and caches it for later saving if
desired. If no name is provided, user will be prompted for one. Descriptions
may be provided, but will default to 'no description'
def options(opts)
opts.banner <<-BANNER
Usage: #{command_name}

Stops recording a macro, loads the command, and caches it for later saving if desired.
BANNER
end

def setup
if !_pry_.instance_variable_defined?(:@record_stack) && _pry_.record_stack.empty?
raise 'Cannot stop recording when no recorder is running'
end
def setup
if !_pry_.instance_variable_defined?(:@record_stack) && _pry_.record_stack.empty?
raise 'Cannot stop macro when macro is not start.'
zw963 marked this conversation as resolved.
Show resolved Hide resolved
end

session_begin = _pry_.record_stack.pop
session_end = Pry.history.session_line_count
session_begin = _pry_.record_stack.pop
session_end = Pry.history.session_line_count

# Get the history between the start and end of the recording session
@history =
Pry.history
.to_a
.last(session_end - session_begin - 1)
.reduce(StringIO.new) { |io, item| io.puts(item); io }
end
# Get the history between the start and end of the recording session
session_history = Pry.history.to_a.last(session_end - session_begin)[0..-2].reject {|e| e == 'edit' }
@history = session_history.each_with_object(StringIO.new) {|history, io| io.puts(history) }
end

def options(opts)
opts.on :n, :name, "Name to use to define the macro",
optional_argument: true, as: String
opts.on :d, :desc, "Description of the macro",
optional_argument: true, as: String
opts.on :v, :verbose, "Echoes back the macro definition"
end
def process
# Have to have a name to execute this later
opts = _pry_.pry_macro_options

def process
# Have to have a name to execute this later
name = opts[:n] || ask('Macro Name: ')
desc = opts[:d] || 'no description'
name = opts[:name]
desc = opts[:desc] || 'no description'

history_lines = @history.string.lines.map { |s| " #{s}"}.join.chomp.tap { |h|
h.sub!(/^ {6}/,'') # First line won't need the spacing
}
history_lines = @history.string.lines.map { |s| " #{s}"}.join.chomp.tap { |h|
zw963 marked this conversation as resolved.
Show resolved Hide resolved
h.sub!(/^ {6}/, '') # First line won't need the spacing
}

# Save the command into a string, and make it look decent
# Tinge of a heredocs hack
command_string = <<-COMMAND_STRING.gsub(/^ {10}/, '')
# Save the command into a string, and make it look decent
# Tinge of a heredocs hack
command_string = <<-COMMAND_STRING.gsub(/^ {10}/, '')
Pry::Commands.block_command '#{name}', '#{desc}' do
_pry_.input = StringIO.new(
<<-MACRO.gsub(/^ {4,6}/, '')
Expand All @@ -80,43 +82,44 @@ def process
end
COMMAND_STRING

puts command_string if opts[:v]
output.puts command_string if opts[:verbose]

# ...so that we can save the contents for saving later (optional)
_pry_.macro_strings << MacroString.new(name, command_string)
# ...as well as evaluating it and making it immediately usable to us.
eval command_string
end
# ...so that we can save the contents for saving later (optional)
_pry_.macro_strings << MacroString.new(name, command_string)
# ...as well as evaluating it and making it immediately usable to us.
eval command_string
end
end

Pry.commands.create_command 'macro-save' do
description 'Save cached macro.'

create_command 'save-macro', 'Saves a named macro to your .pryrc file on the tail end' do
banner <<-BANNER
Usage: save-macro [-p path]
def options(opts)
opts.banner <<-BANNER
Usage: #{command_name} name

Saves a cached macro to your ~/.pryrc or the path specified.
Saves a cached macro to your ~/.pry-macro.
BANNER
end

def options(opts)
opts.on :p, :path, "Pathname to save macro in",
optional_argument: true, as: String
end
def process
raise 'No Macros are defined!' unless _pry_.instance_variable_defined?(:@macro_strings)
raise Pry::CommandError, "The command '#{command_name}' must specify a macro name to execute later!" if args.empty?

def process
raise 'No Macros are defined!' unless _pry_.instance_variable_defined?(:@macro_strings)
raise 'Invalid path!' if opts[:p] && !Dir[opts[:p]]
raise 'Must specify the macro to save!' if args.empty?
path = Dir.home
macro = _pry_.macro_strings.find(
# If nothing is found, raise the error
-> { raise "Command #{args.first} not found!" }
) { |m| m.name == args.first }

path = opts[:p] || Dir.home
macro = _pry_.macro_strings.find(
# If nothing is found, raise the error
-> { raise "Command #{args.first} not found!" }
) { |m| m.name == args.first }
dot_pryrc = File.readlines("#{Dir.home}/.pryrc")

# Append the Pryrc with the macro, leaving blank lines
File.open(File.join(path, '.pryrc'), 'a') { |f| f.puts '', macro.command, '' }
if dot_pryrc.grep(%r{^\s*load \"\#\{Dir.home\}/\.pry-macro\"}).empty?
File.open(File.join(path, '.pryrc'), 'a') { |f| f.puts '', 'load "#{Dir.home}/.pry-macro"' }
end

# Append new macro to ~/.pry-macro
File.open(File.join(path, '.pry-macro'), 'a') { |f| f.puts '', macro.command }
end
end
end

Pry.commands.import PryMacro::Commands
2 changes: 1 addition & 1 deletion lib/pry-macro/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module PryMacro
VERSION = '1.0.1'
VERSION = '2.0.1'
end
3 changes: 1 addition & 2 deletions pry-macro.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
spec.name = "pry-macro"
spec.version = PryMacro::VERSION
spec.authors = ["Brandon Weaver"]
spec.email = ["keystonelemur@gmail.com"]
spec.email = ["keystonelemur@gmail.com", 'vil963@gmail.com']
spec.summary = %q{Macros for Pry}
spec.description = %q{Macro Recording and Saving functionality for pry}
spec.homepage = "https://github.com/baweaver/pry-macro"
Expand All @@ -25,5 +25,4 @@ Gem::Specification.new do |spec|
spec.add_development_dependency "guard-rspec"

spec.add_runtime_dependency "pry"
spec.add_runtime_dependency 'highline'
end