ruby-shell 3.4.8 → 3.5.0

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 (3) hide show
  1. checksums.yaml +4 -4
  2. data/bin/rsh +144 -21
  3. metadata +5 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 35dd4b1b6792ae0a66b0da2efd24bf78af5f2ba268fd933bd0af2b43e7fb0b23
4
- data.tar.gz: 6c1f6026a8870e178788190f702de82f3845364ebaa4e42a9952a8f9b61d9d0e
3
+ metadata.gz: bac3cf4ea368be8c2991ee650e1977c7fafd7b1548645c1e3daaa94fd29bae2d
4
+ data.tar.gz: 31b8ae6ffcf460c7a236c72c8188254243879ab8b83ac690fcf8e61fc0aa46ad
5
5
  SHA512:
6
- metadata.gz: e9a950baff3af17ae641fe67a9782b5888c4e1ce93a94354558ec39adecbbe9254710a5719a000254c326eb71d9b91b098edea77dcdedcf773baff269448fa5c
7
- data.tar.gz: a84ce4e143a9237549affdb6befd894adf032737ae949edd4e326fe8858a127158f976760bfb43e41b6e51f8b58cf62e0271ebfec1cfa41e6b8f67763ecbe957
6
+ metadata.gz: bb8eb4cef6df5403bc751cf29d440a4289877fd9f7684f153e82196a3f24e425f88fabbe2ccae63c0ef108cae205feb241e84b52f138ad07975d03bd38834a7b
7
+ data.tar.gz: 96eb9e448ffd6c20b469e1b0d0f11e7f8dc274e809c4cc543dea3aa7ff5b5a5121a1aae6de7522cb3af1b3ff59e8e655df7af68ed54322f96844c5df910b4904
data/bin/rsh CHANGED
@@ -8,7 +8,7 @@
8
8
  # Web_site: http://isene.com/
9
9
  # Github: https://github.com/isene/rsh
10
10
  # License: Public domain
11
- @version = "3.4.8" # Code refactoring: DRY helpers, nick/gnick feedback, bug fixes
11
+ @version = "3.5.0" # Polish release: Nick/history export, default nicks, expanded completions, startup tips, validation templates
12
12
 
13
13
  # MODULES, CLASSES AND EXTENSIONS
14
14
  class String # Add coloring to strings (with escaping for Readline)
@@ -137,8 +137,18 @@ begin # Initialization
137
137
  "cargo" => %w[build run test check clean doc new init add search publish install update],
138
138
  "npm" => %w[install uninstall update run build test start init publish],
139
139
  "gem" => %w[install uninstall update list search build push],
140
- "bundle" => %w[install update exec check config]
140
+ "bundle" => %w[install update exec check config],
141
+ "kubectl" => %w[get describe create delete apply edit logs exec port-forward scale rollout top explain diff patch],
142
+ "terraform" => %w[init plan apply destroy import output show],
143
+ "aws" => %w[s3 ec2 lambda cloudformation iam rds dynamodb sns sqs],
144
+ "brew" => %w[install uninstall update upgrade search info list],
145
+ "yarn" => %w[add remove install build test start init],
146
+ "make" => %w[clean install build test all],
147
+ "ansible" => %w[playbook galaxy vault inventory],
148
+ "poetry" => %w[add remove install update build publish],
149
+ "pipenv" => %w[install uninstall update shell run]
141
150
  }
151
+ @show_tips = true # Show startup tips (configurable)
142
152
  # New v3.0 features initialization
143
153
  @switch_cache = {} # Cache for command switches from --help
144
154
  @switch_cache_time = {} # Timestamp for cache expiry
@@ -277,7 +287,9 @@ def firstrun
277
287
  @completion_show_descriptions = false # Show help text inline
278
288
  @completion_fuzzy = true # Enable fuzzy matching
279
289
 
280
- @nick = {"ls"=>"ls --color -F"}
290
+ @nick = {
291
+ "ls" => "ls --color -F"
292
+ }
281
293
  RSHRC
282
294
  File.write(Dir.home+'/.rshrc', rc)
283
295
  end
@@ -1063,11 +1075,25 @@ def suggest_command(cmd) # Smart command suggestions for typos
1063
1075
  return nil if cmd.nil? || cmd.empty?
1064
1076
  return nil if @exe.include?(cmd) || @nick.include?(cmd)
1065
1077
 
1078
+ max_dist = [cmd.length / 3, 2].max
1079
+
1080
+ # Pre-filter by length and first letter (huge optimization for large @exe)
1081
+ length_range = (cmd.length - max_dist)..(cmd.length + max_dist)
1082
+ first_letter = cmd[0]
1083
+
1084
+ # Filter: similar length AND (same first letter OR within 1 char distance)
1085
+ pool = (@exe + @nick.keys).select do |c|
1086
+ c.length >= 2 &&
1087
+ length_range.include?(c.length) &&
1088
+ (c[0] == first_letter || (c[0].ord - first_letter.ord).abs <= 1)
1089
+ end
1090
+
1091
+ # Hard limit to prevent any hang
1092
+ pool = pool.first(100)
1093
+
1066
1094
  # Find commands with small edit distance
1067
- candidates = (@exe + @nick.keys).select do |c|
1068
- next false if c.length < 2
1095
+ candidates = pool.select do |c|
1069
1096
  dist = levenshtein_distance(cmd, c)
1070
- max_dist = [cmd.length / 3, 2].max
1071
1097
  dist <= max_dist && dist > 0
1072
1098
  end
1073
1099
 
@@ -1115,6 +1141,7 @@ def config(*args) # Configure rsh settings
1115
1141
  puts " auto_correct: #{@auto_correct ? 'on' : 'off'}"
1116
1142
  puts " slow_command_threshold: #{@slow_command_threshold}s #{@slow_command_threshold > 0 ? '(enabled)' : '(disabled)'}"
1117
1143
  puts " completion_learning: #{@completion_learning ? 'on' : 'off'}"
1144
+ puts " show_tips: #{@show_tips ? 'on' : 'off'}"
1118
1145
  puts " completion_limit: #{@completion_limit}"
1119
1146
  puts " completion_fuzzy: #{@completion_fuzzy}"
1120
1147
  puts " completion_case_sensitive: #{@completion_case_sensitive}"
@@ -1155,9 +1182,13 @@ def config(*args) # Configure rsh settings
1155
1182
  @completion_show_metadata = %w[on true yes 1].include?(value.to_s.downcase)
1156
1183
  puts "Completion metadata display #{@completion_show_metadata ? 'enabled' : 'disabled'}"
1157
1184
  rshrc
1185
+ when 'show_tips'
1186
+ @show_tips = %w[on true yes 1].include?(value.to_s.downcase)
1187
+ puts "Startup tips #{@show_tips ? 'enabled' : 'disabled'}"
1188
+ rshrc
1158
1189
  else
1159
1190
  puts "Unknown setting '#{setting}'"
1160
- puts "Available: history_dedup, session_autosave, auto_correct, slow_command_threshold, completion_learning, completion_limit, completion_show_metadata"
1191
+ puts "Available: history_dedup, session_autosave, auto_correct, slow_command_threshold, completion_learning, show_tips, completion_limit"
1161
1192
  end
1162
1193
  end
1163
1194
  def env(*args) # Environment variable management
@@ -1588,15 +1619,38 @@ def help
1588
1619
  end
1589
1620
  puts
1590
1621
  end
1591
- def info
1592
- puts @info
1622
+ def info(*args)
1623
+ option = args[0]
1624
+
1625
+ if option == '--quick'
1626
+ puts "\nrsh v#{@version} - Ruby SHell"
1627
+ puts "Type :help for commands, :info for full intro"
1628
+ elsif option == '--features'
1629
+ puts "\nKey Features:"
1630
+ puts "• Nicks (aliases) with {{parameters}}"
1631
+ puts "• Completion learning (adapts to you)"
1632
+ puts "• Command recording & replay"
1633
+ puts "• Plugin system"
1634
+ puts "• Stats & analytics"
1635
+ puts "• 6 color themes"
1636
+ puts "• AI integration"
1637
+ puts "Type :help for details"
1638
+ else
1639
+ puts @info
1640
+ end
1593
1641
  end
1594
1642
  def version
1595
1643
  puts "rsh version = #{@version} (latest RubyGems version is #{Gem.latest_version_for("ruby-shell").version} - https://github.com/isene/rsh)"
1596
1644
  end
1597
- def history # Show most recent history (up to 50 entries)
1598
- puts "History:"
1599
- @history.each_with_index {|h,i| puts i.to_s + "; " + h if i < 50}
1645
+ def history(*args) # Show most recent history (up to 50 entries)
1646
+ if args[0] == '--export'
1647
+ filename = args[1] || 'history.txt'
1648
+ File.write(filename, @history.join("\n"))
1649
+ puts "History exported to #{filename} (#{@history.length} commands)"
1650
+ else
1651
+ puts "History:"
1652
+ @history.each_with_index {|h,i| puts i.to_s + "; " + h if i < 50}
1653
+ end
1600
1654
  end
1601
1655
  def rmhistory # Delete history
1602
1656
  @history = []
@@ -1620,6 +1674,19 @@ def nick(nick_str = nil) # Define a new nick like this: `:nick "ls = ls --color
1620
1674
  @nick.sort.each {|key, value| puts " #{key.c(@c_nick)} = #{value}"}
1621
1675
  end
1622
1676
  puts
1677
+ elsif nick_str =~ /^--export\s*(.*)/
1678
+ filename = $1.strip.empty? ? 'nicks.json' : $1.strip
1679
+ require 'json' unless defined?(JSON)
1680
+ File.write(filename, JSON.pretty_generate(@nick))
1681
+ puts "Nicks exported to #{filename}"
1682
+ elsif nick_str =~ /^--import\s+(.*)/
1683
+ filename = $1.strip
1684
+ return puts "File '#{filename}' not found" unless File.exist?(filename)
1685
+ require 'json' unless defined?(JSON)
1686
+ imported = JSON.parse(File.read(filename))
1687
+ imported.each { |k, v| @nick[k] = v }
1688
+ puts "Imported #{imported.length} nicks"
1689
+ rshrc
1623
1690
  elsif nick_str.match(/^\s*-/)
1624
1691
  source = nick_str.sub(/^\s*-/, '')
1625
1692
  if @nick.delete(source)
@@ -2515,24 +2582,46 @@ def validate_command(cmd) # Syntax validation before execution
2515
2582
  end
2516
2583
  def calc(*args) # Inline calculator using Ruby's Math library
2517
2584
  if args.empty?
2518
- puts "Usage: calc <expression>"
2585
+ puts "Usage: :calc <expression>"
2519
2586
  puts "Examples:"
2520
- puts " calc 2 + 2"
2521
- puts " calc \"Math.sqrt(16)\""
2522
- puts " calc \"Math::PI * 2\""
2587
+ puts " :calc 2 + 2"
2588
+ puts " :calc Math.sqrt(16)"
2589
+ puts " :calc Math::PI * 2"
2590
+ puts " :calc sin(PI/4)"
2591
+ puts "Available: +, -, *, /, **, %, sqrt, sin, cos, tan, log, exp, abs, PI, E, etc."
2523
2592
  return
2524
2593
  end
2525
2594
 
2526
2595
  expression = args.join(' ')
2527
2596
 
2597
+ # Create sandbox with Math module for safer evaluation
2598
+ sandbox = Object.new
2599
+ sandbox.extend(Math)
2600
+
2528
2601
  begin
2529
- # Safe evaluation with Math library
2530
- result = eval(expression, binding, __FILE__, __LINE__)
2602
+ result = sandbox.instance_eval(expression)
2531
2603
  puts result
2604
+ rescue ZeroDivisionError
2605
+ puts "Error: Division by zero"
2606
+ rescue NameError => e
2607
+ # Extract the undefined name (sandbox format)
2608
+ if e.message =~ /undefined method `(\w+)'/
2609
+ undefined = $1
2610
+ puts "Error: Unknown function '#{undefined}'"
2611
+ puts "Available Math functions: sqrt, sin, cos, tan, log, exp, abs, ceil, floor, round"
2612
+ puts "Constants: PI, E"
2613
+ else
2614
+ puts "Error: #{e.message}"
2615
+ end
2532
2616
  rescue SyntaxError => e
2533
- puts "Syntax error in expression: #{e.message}"
2617
+ puts "Error: Invalid expression syntax"
2618
+ puts "Check parentheses, operators, and spacing"
2619
+ rescue ArgumentError => e
2620
+ puts "Error: Invalid argument - #{e.message}"
2621
+ rescue TypeError => e
2622
+ puts "Error: Type mismatch - #{e.message}"
2534
2623
  rescue => e
2535
- puts "Error evaluating expression: #{e.message}"
2624
+ puts "Error: #{e.message}"
2536
2625
  end
2537
2626
  end
2538
2627
  def validate(rule_str = nil) # Custom validation rule management
@@ -2542,6 +2631,7 @@ def validate(rule_str = nil) # Custom validation rule management
2542
2631
  puts "\nNo validation rules defined"
2543
2632
  puts "Usage: :validate pattern = action"
2544
2633
  puts "Actions: block, confirm, warn, log"
2634
+ puts "Or try: :validate --templates"
2545
2635
  return
2546
2636
  end
2547
2637
  puts "\n Validation Rules:".c(@c_prompt).b
@@ -2549,6 +2639,21 @@ def validate(rule_str = nil) # Custom validation rule management
2549
2639
  puts " #{i+1}. #{rule[:pattern].inspect} → #{rule[:action]}"
2550
2640
  end
2551
2641
  puts
2642
+ elsif rule_str == '--templates'
2643
+ puts "\n Common Validation Rule Templates:".c(@c_prompt).b
2644
+ puts " Safety:"
2645
+ puts " :validate rm -rf / = block"
2646
+ puts " :validate DROP TABLE = block"
2647
+ puts " Confirmation:"
2648
+ puts " :validate git push --force = confirm"
2649
+ puts " :validate npm publish = confirm"
2650
+ puts " Warnings:"
2651
+ puts " :validate sudo = warn"
2652
+ puts " :validate chmod 777 = warn"
2653
+ puts " Logging:"
2654
+ puts " :validate npm install = log"
2655
+ puts " :validate pip install = log"
2656
+ puts
2552
2657
  elsif rule_str =~ /^-(\d+)$/
2553
2658
  # Delete rule by index
2554
2659
  index = $1.to_i - 1
@@ -3373,6 +3478,20 @@ loop do
3373
3478
  unless @plugins_loaded
3374
3479
  load_plugins
3375
3480
  @plugins_loaded = true
3481
+ # Show startup tip (30% chance, if enabled)
3482
+ if @show_tips && rand < 0.3
3483
+ tips = [
3484
+ "Tip: Use :nick gp={{branch}} for parametrized aliases!",
3485
+ "Tip: Press Ctrl-G to edit commands in $EDITOR",
3486
+ "Tip: :stats --graph shows visual analytics",
3487
+ "Tip: :record your workflows and :replay them later",
3488
+ "Tip: :validate rm -rf / = block for safety rules",
3489
+ "Tip: :completion_stats shows what you use most",
3490
+ "Tip: Type :help for quick reference",
3491
+ "Tip: Disable tips with: :config show_tips off"
3492
+ ]
3493
+ puts tips.sample.c(244)
3494
+ end
3376
3495
  end
3377
3496
  # Build display prompt with plugin additions (don't modify @prompt)
3378
3497
  plugin_prompts = call_plugin_hook(:on_prompt)
@@ -3600,11 +3719,12 @@ loop do
3600
3719
  puts "Bookmark '#{@cmd}' points to non-existent directory: #{bm_dir}".c(196)
3601
3720
  end
3602
3721
  else
3603
- puts "#{Time.now.strftime("%H:%M:%S")}: #{@cmd}".c(@c_stamp)
3604
3722
  if @cmd == "f" # fzf integration (https://github.com/junegunn/fzf)
3723
+ puts "#{Time.now.strftime("%H:%M:%S")}: #{@cmd}".c(@c_stamp)
3605
3724
  res = `fzf`.chomp
3606
3725
  Dir.chdir(File.dirname(res))
3607
3726
  elsif File.exist?(@cmd) and not File.executable?(@cmd) and not @cmd.include?(" ")
3727
+ puts "#{Time.now.strftime("%H:%M:%S")}: #{@cmd}".c(@c_stamp)
3608
3728
  # Only auto-open files if it's a single filename (no spaces = no command with args)
3609
3729
  if File.read(@cmd).force_encoding("UTF-8").valid_encoding?
3610
3730
  system("#{ENV['EDITOR']} #{@cmd}") # Try open with user's editor
@@ -3622,6 +3742,9 @@ loop do
3622
3742
  # Apply auto-correct if enabled (before validation)
3623
3743
  @cmd = apply_auto_correct(@cmd)
3624
3744
 
3745
+ # Print timestamp AFTER auto-correct (shows what actually executes)
3746
+ puts "#{Time.now.strftime("%H:%M:%S")}: #{@cmd}".c(@c_stamp)
3747
+
3625
3748
  # Validate command after auto-correction
3626
3749
  warnings = validate_command(@cmd)
3627
3750
  if warnings && !warnings.empty?
metadata CHANGED
@@ -1,19 +1,20 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-shell
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.8
4
+ version: 3.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Geir Isene
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-10-29 00:00:00.000000000 Z
11
+ date: 2025-10-30 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: 'A shell written in Ruby with extensive tab completions, aliases/nicks,
14
14
  history, syntax highlighting, theming, auto-cd, auto-opening files and more. UPDATE
15
- v3.4.8: Code refactoring with DRY helpers (ensure_type, persist_var), nick/gnick
16
- feedback messages, fixed @plugin_enabled bug. Cleaner, more maintainable codebase!'
15
+ v3.5.0: Nick/history export, 9 new tool completions (kubectl, terraform, aws, brew,
16
+ etc.), validation templates, startup tips, improved :info, aggressive suggest_command
17
+ optimization for huge PATHs (18K+ executables), timestamp shows corrected commands!'
17
18
  email: g@isene.com
18
19
  executables:
19
20
  - rsh