ruby-shell 3.4.7 → 3.4.9
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.
- checksums.yaml +4 -4
- data/bin/rsh +108 -73
- metadata +5 -5
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: c2eadccdac83c394da85a64a138d36cad24de2603aeb2867bce52f4aa00d0568
         | 
| 4 | 
            +
              data.tar.gz: 0b54ea26c9f82db1f1c29fffbc6e69d19c0c4ad3e5d94d490ba33aaf268be3c5
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 8448bde19ed12fb02b3b28a7295f928ce643caa43ce7045f8693a733729bd8dea2b23c01cbae44fcf3d39f412238a5aa5a17281e9d55cf64f5ec2bf5c56fe38d
         | 
| 7 | 
            +
              data.tar.gz: bd903733344c8aa9b0d42a2dfbcaf63339861bc7db5a289425881fea0a8c10fcbfc705a0840000ef165a99a843ebdd39c155263fe393fbd09ce8885dad6513c0
         | 
    
        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. | 
| 11 | 
            +
            @version    = "3.4.9" # Improved :calc with safer eval, Math sandbox, better error messages
         | 
| 12 12 |  | 
| 13 13 | 
             
            # MODULES, CLASSES AND EXTENSIONS
         | 
| 14 14 | 
             
            class String # Add coloring to strings (with escaping for Readline)
         | 
| @@ -1077,6 +1077,16 @@ def suggest_command(cmd) # Smart command suggestions for typos | |
| 1077 1077 | 
             
              candidates.sort_by! { |c| levenshtein_distance(cmd, c) }
         | 
| 1078 1078 | 
             
              candidates.first(3)
         | 
| 1079 1079 | 
             
            end
         | 
| 1080 | 
            +
            def ensure_type(var_name, type, default) # Helper to ensure instance variable has correct type
         | 
| 1081 | 
            +
              var = instance_variable_get(var_name)
         | 
| 1082 | 
            +
              instance_variable_set(var_name, default) unless var.is_a?(type)
         | 
| 1083 | 
            +
            end
         | 
| 1084 | 
            +
            def persist_var(conf, var_name, value, condition = true) # Helper to persist variable to config
         | 
| 1085 | 
            +
              return conf unless condition
         | 
| 1086 | 
            +
              conf.sub!(/^#{Regexp.escape(var_name)}.*(\n|$)/, "")
         | 
| 1087 | 
            +
              conf += "#{var_name} = #{value.inspect}\n"
         | 
| 1088 | 
            +
              conf
         | 
| 1089 | 
            +
            end
         | 
| 1080 1090 | 
             
            def hist_clean # Clean up @history
         | 
| 1081 1091 | 
             
              @history.compact!
         | 
| 1082 1092 | 
             
              @history.delete("")
         | 
| @@ -1378,31 +1388,19 @@ def rshrc # Write user configuration to .rshrc (portable between machines) | |
| 1378 1388 | 
             
                conf = ""
         | 
| 1379 1389 | 
             
              end
         | 
| 1380 1390 |  | 
| 1381 | 
            -
              #  | 
| 1382 | 
            -
              conf | 
| 1383 | 
            -
              conf  | 
| 1384 | 
            -
              conf | 
| 1385 | 
            -
              conf  | 
| 1386 | 
            -
              conf | 
| 1387 | 
            -
              conf  | 
| 1388 | 
            -
              conf | 
| 1389 | 
            -
              conf  | 
| 1390 | 
            -
              conf | 
| 1391 | 
            -
              conf  | 
| 1392 | 
            -
              conf | 
| 1393 | 
            -
              conf  | 
| 1394 | 
            -
              conf.sub!(/^@auto_correct.*(\n|$)/, "")
         | 
| 1395 | 
            -
              conf += "@auto_correct = #{@auto_correct}\n" if @auto_correct
         | 
| 1396 | 
            -
              conf.sub!(/^@slow_command_threshold.*(\n|$)/, "")
         | 
| 1397 | 
            -
              conf += "@slow_command_threshold = #{@slow_command_threshold}\n" if @slow_command_threshold && @slow_command_threshold > 0
         | 
| 1398 | 
            -
              conf.sub!(/^@completion_learning.*(\n|$)/, "")
         | 
| 1399 | 
            -
              conf += "@completion_learning = #{@completion_learning}\n" unless @completion_learning
         | 
| 1400 | 
            -
              conf.sub!(/^@completion_show_metadata.*(\n|$)/, "")
         | 
| 1401 | 
            -
              conf += "@completion_show_metadata = #{@completion_show_metadata}\n" if @completion_show_metadata
         | 
| 1402 | 
            -
              conf.sub!(/^@plugin_enabled.*(\n|$)/, "")
         | 
| 1403 | 
            -
              conf += "@plugin_enabled = #{@plugin_enabled}\n" unless @plugin_enabled.empty?
         | 
| 1404 | 
            -
              conf.sub!(/^@validation_rules.*(\n|$)/, "")
         | 
| 1405 | 
            -
              conf += "@validation_rules = #{@validation_rules}\n" unless @validation_rules.empty?
         | 
| 1391 | 
            +
              # Persist user-editable configuration using helper
         | 
| 1392 | 
            +
              conf = persist_var(conf, '@nick', @nick)
         | 
| 1393 | 
            +
              conf = persist_var(conf, '@gnick', @gnick)
         | 
| 1394 | 
            +
              conf = persist_var(conf, '@bookmarks', @bookmarks, !@bookmarks.empty?)
         | 
| 1395 | 
            +
              conf = persist_var(conf, '@defuns', @defuns, !@defuns.empty?)
         | 
| 1396 | 
            +
              conf = persist_var(conf, '@history_dedup', @history_dedup, @history_dedup && @history_dedup != 'smart')
         | 
| 1397 | 
            +
              conf = persist_var(conf, '@session_autosave', @session_autosave, @session_autosave && @session_autosave > 0)
         | 
| 1398 | 
            +
              conf = persist_var(conf, '@auto_correct', @auto_correct, @auto_correct)
         | 
| 1399 | 
            +
              conf = persist_var(conf, '@slow_command_threshold', @slow_command_threshold, @slow_command_threshold && @slow_command_threshold > 0)
         | 
| 1400 | 
            +
              conf = persist_var(conf, '@completion_learning', @completion_learning, !@completion_learning)
         | 
| 1401 | 
            +
              conf = persist_var(conf, '@completion_show_metadata', @completion_show_metadata, @completion_show_metadata)
         | 
| 1402 | 
            +
              conf = persist_var(conf, '@plugin_disabled', @plugin_disabled, !@plugin_disabled.empty?)
         | 
| 1403 | 
            +
              conf = persist_var(conf, '@validation_rules', @validation_rules, !@validation_rules.empty?)
         | 
| 1406 1404 |  | 
| 1407 1405 | 
             
              File.write(Dir.home+'/.rshrc', conf)
         | 
| 1408 1406 | 
             
              rshstate  # Also save runtime state
         | 
| @@ -1562,6 +1560,8 @@ def help | |
| 1562 1560 | 
             
              col3 << ":help        This help"
         | 
| 1563 1561 | 
             
              col3 << ":info        About rsh"
         | 
| 1564 1562 | 
             
              col3 << ":version     Version info"
         | 
| 1563 | 
            +
              col3 << ":history     Show history"
         | 
| 1564 | 
            +
              col3 << ":rehash      Rebuild cache"
         | 
| 1565 1565 |  | 
| 1566 1566 | 
             
              # Pad columns to same length
         | 
| 1567 1567 | 
             
              max_lines = [col1.length, col2.length, col3.length].max
         | 
| @@ -1622,12 +1622,17 @@ def nick(nick_str = nil)  # Define a new nick like this: `:nick "ls = ls --color | |
| 1622 1622 | 
             
                puts
         | 
| 1623 1623 | 
             
              elsif nick_str.match(/^\s*-/)
         | 
| 1624 1624 | 
             
                source = nick_str.sub(/^\s*-/, '')
         | 
| 1625 | 
            -
                @nick.delete(source)
         | 
| 1626 | 
            -
             | 
| 1625 | 
            +
                if @nick.delete(source)
         | 
| 1626 | 
            +
                  puts "Nick '#{source}' deleted"
         | 
| 1627 | 
            +
                  rshrc
         | 
| 1628 | 
            +
                else
         | 
| 1629 | 
            +
                  puts "Nick '#{source}' not found"
         | 
| 1630 | 
            +
                end
         | 
| 1627 1631 | 
             
              else
         | 
| 1628 1632 | 
             
                source = nick_str.sub(/ =.*/, '')
         | 
| 1629 1633 | 
             
                target = nick_str.sub(/.*= /, '')
         | 
| 1630 1634 | 
             
                @nick[source] = target
         | 
| 1635 | 
            +
                puts "Nick '#{source}' → '#{target}'"
         | 
| 1631 1636 | 
             
                rshrc
         | 
| 1632 1637 | 
             
              end
         | 
| 1633 1638 | 
             
            end
         | 
| @@ -1643,12 +1648,17 @@ def gnick(nick_str = nil) # Define a generic/global nick to match not only comma | |
| 1643 1648 | 
             
                puts
         | 
| 1644 1649 | 
             
              elsif nick_str.match(/^\s*-/)
         | 
| 1645 1650 | 
             
                source = nick_str.sub(/^\s*-/, '')
         | 
| 1646 | 
            -
                @gnick.delete(source)
         | 
| 1647 | 
            -
             | 
| 1651 | 
            +
                if @gnick.delete(source)
         | 
| 1652 | 
            +
                  puts "Gnick '#{source}' deleted"
         | 
| 1653 | 
            +
                  rshrc
         | 
| 1654 | 
            +
                else
         | 
| 1655 | 
            +
                  puts "Gnick '#{source}' not found"
         | 
| 1656 | 
            +
                end
         | 
| 1648 1657 | 
             
              else
         | 
| 1649 1658 | 
             
                source = nick_str.sub(/ =.*/, '')
         | 
| 1650 1659 | 
             
                target = nick_str.sub(/.*= /, '')
         | 
| 1651 1660 | 
             
                @gnick[source] = target
         | 
| 1661 | 
            +
                puts "Gnick '#{source}' → '#{target}'"
         | 
| 1652 1662 | 
             
                rshrc
         | 
| 1653 1663 | 
             
              end
         | 
| 1654 1664 | 
             
            end
         | 
| @@ -2505,24 +2515,46 @@ def validate_command(cmd) # Syntax validation before execution | |
| 2505 2515 | 
             
            end
         | 
| 2506 2516 | 
             
            def calc(*args) # Inline calculator using Ruby's Math library
         | 
| 2507 2517 | 
             
              if args.empty?
         | 
| 2508 | 
            -
                puts "Usage: calc <expression>"
         | 
| 2518 | 
            +
                puts "Usage: :calc <expression>"
         | 
| 2509 2519 | 
             
                puts "Examples:"
         | 
| 2510 | 
            -
                puts "  calc 2 + 2"
         | 
| 2511 | 
            -
                puts "  calc  | 
| 2512 | 
            -
                puts "  calc  | 
| 2520 | 
            +
                puts "  :calc 2 + 2"
         | 
| 2521 | 
            +
                puts "  :calc Math.sqrt(16)"
         | 
| 2522 | 
            +
                puts "  :calc Math::PI * 2"
         | 
| 2523 | 
            +
                puts "  :calc sin(PI/4)"
         | 
| 2524 | 
            +
                puts "Available: +, -, *, /, **, %, sqrt, sin, cos, tan, log, exp, abs, PI, E, etc."
         | 
| 2513 2525 | 
             
                return
         | 
| 2514 2526 | 
             
              end
         | 
| 2515 2527 |  | 
| 2516 2528 | 
             
              expression = args.join(' ')
         | 
| 2517 2529 |  | 
| 2530 | 
            +
              # Create sandbox with Math module for safer evaluation
         | 
| 2531 | 
            +
              sandbox = Object.new
         | 
| 2532 | 
            +
              sandbox.extend(Math)
         | 
| 2533 | 
            +
             | 
| 2518 2534 | 
             
              begin
         | 
| 2519 | 
            -
                 | 
| 2520 | 
            -
                result = eval(expression, binding, __FILE__, __LINE__)
         | 
| 2535 | 
            +
                result = sandbox.instance_eval(expression)
         | 
| 2521 2536 | 
             
                puts result
         | 
| 2537 | 
            +
              rescue ZeroDivisionError
         | 
| 2538 | 
            +
                puts "Error: Division by zero"
         | 
| 2539 | 
            +
              rescue NameError => e
         | 
| 2540 | 
            +
                # Extract the undefined name
         | 
| 2541 | 
            +
                if e.message =~ /undefined local variable or method `(\w+)'/
         | 
| 2542 | 
            +
                  undefined = $1
         | 
| 2543 | 
            +
                  puts "Error: Unknown function or variable '#{undefined}'"
         | 
| 2544 | 
            +
                  puts "Available Math functions: sqrt, sin, cos, tan, log, exp, abs, ceil, floor, round"
         | 
| 2545 | 
            +
                  puts "Constants: PI, E"
         | 
| 2546 | 
            +
                else
         | 
| 2547 | 
            +
                  puts "Error: #{e.message}"
         | 
| 2548 | 
            +
                end
         | 
| 2522 2549 | 
             
              rescue SyntaxError => e
         | 
| 2523 | 
            -
                puts " | 
| 2550 | 
            +
                puts "Error: Invalid expression syntax"
         | 
| 2551 | 
            +
                puts "Check parentheses, operators, and spacing"
         | 
| 2552 | 
            +
              rescue ArgumentError => e
         | 
| 2553 | 
            +
                puts "Error: Invalid argument - #{e.message}"
         | 
| 2554 | 
            +
              rescue TypeError => e
         | 
| 2555 | 
            +
                puts "Error: Type mismatch - #{e.message}"
         | 
| 2524 2556 | 
             
              rescue => e
         | 
| 2525 | 
            -
                puts "Error | 
| 2557 | 
            +
                puts "Error: #{e.message}"
         | 
| 2526 2558 | 
             
              end
         | 
| 2527 2559 | 
             
            end
         | 
| 2528 2560 | 
             
            def validate(rule_str = nil) # Custom validation rule management
         | 
| @@ -3055,26 +3087,26 @@ def load_rshrc_safe | |
| 3055 3087 | 
             
                # Try to load the .rshrc file
         | 
| 3056 3088 | 
             
                load(Dir.home+'/.rshrc')
         | 
| 3057 3089 |  | 
| 3058 | 
            -
                # Validate critical variables
         | 
| 3059 | 
            -
                 | 
| 3060 | 
            -
                 | 
| 3061 | 
            -
                 | 
| 3062 | 
            -
                 | 
| 3063 | 
            -
                 | 
| 3064 | 
            -
                 | 
| 3065 | 
            -
                 | 
| 3066 | 
            -
                 | 
| 3067 | 
            -
                 | 
| 3068 | 
            -
                 | 
| 3069 | 
            -
                 | 
| 3070 | 
            -
                 | 
| 3071 | 
            -
                 | 
| 3072 | 
            -
                 | 
| 3073 | 
            -
                 | 
| 3074 | 
            -
                 | 
| 3090 | 
            +
                # Validate critical variables using helper
         | 
| 3091 | 
            +
                ensure_type(:@history, Array, [])
         | 
| 3092 | 
            +
                ensure_type(:@nick, Hash, {})
         | 
| 3093 | 
            +
                ensure_type(:@gnick, Hash, {})
         | 
| 3094 | 
            +
                ensure_type(:@cmd_frequency, Hash, {})
         | 
| 3095 | 
            +
                ensure_type(:@cmd_stats, Hash, {})
         | 
| 3096 | 
            +
                ensure_type(:@bookmarks, Hash, {})
         | 
| 3097 | 
            +
                ensure_type(:@defuns, Hash, {})
         | 
| 3098 | 
            +
                ensure_type(:@history_dedup, String, 'smart')
         | 
| 3099 | 
            +
                ensure_type(:@session_autosave, Integer, 0)
         | 
| 3100 | 
            +
                ensure_type(:@slow_command_threshold, Integer, 0)
         | 
| 3101 | 
            +
                ensure_type(:@plugin_disabled, Array, [])  # FIXED: was @plugin_enabled
         | 
| 3102 | 
            +
                ensure_type(:@plugins, Array, [])
         | 
| 3103 | 
            +
                ensure_type(:@plugin_commands, Hash, {})
         | 
| 3104 | 
            +
                ensure_type(:@validation_rules, Array, [])
         | 
| 3105 | 
            +
                ensure_type(:@completion_weights, Hash, {})
         | 
| 3106 | 
            +
                ensure_type(:@recording, Hash, {active: false, name: nil, commands: []})
         | 
| 3107 | 
            +
                ensure_type(:@recordings, Hash, {})
         | 
| 3108 | 
            +
                @auto_correct = false unless [true, false].include?(@auto_correct)
         | 
| 3075 3109 | 
             
                @completion_learning = true if @completion_learning.nil?
         | 
| 3076 | 
            -
                @recording = {active: false, name: nil, commands: []} unless @recording.is_a?(Hash)
         | 
| 3077 | 
            -
                @recordings = {} unless @recordings.is_a?(Hash)
         | 
| 3078 3110 |  | 
| 3079 3111 | 
             
                # Restore defuns from .rshrc
         | 
| 3080 3112 | 
             
                if @defuns && !@defuns.empty?
         | 
| @@ -3205,31 +3237,34 @@ def auto_heal_rshrc | |
| 3205 3237 | 
             
            end
         | 
| 3206 3238 |  | 
| 3207 3239 | 
             
            def load_defaults
         | 
| 3208 | 
            -
               | 
| 3209 | 
            -
               | 
| 3210 | 
            -
               | 
| 3240 | 
            +
              # Use ensure_type for consistency
         | 
| 3241 | 
            +
              ensure_type(:@history, Array, [])
         | 
| 3242 | 
            +
              ensure_type(:@nick, Hash, {"ls" => "ls --color -F"})
         | 
| 3243 | 
            +
              ensure_type(:@gnick, Hash, {})
         | 
| 3244 | 
            +
              ensure_type(:@cmd_frequency, Hash, {})
         | 
| 3245 | 
            +
              ensure_type(:@cmd_stats, Hash, {})
         | 
| 3246 | 
            +
              ensure_type(:@bookmarks, Hash, {})
         | 
| 3247 | 
            +
              ensure_type(:@defuns, Hash, {})
         | 
| 3248 | 
            +
              ensure_type(:@switch_cache, Hash, {})
         | 
| 3249 | 
            +
              ensure_type(:@switch_cache_time, Hash, {})
         | 
| 3250 | 
            +
              ensure_type(:@plugin_disabled, Array, [])  # FIXED: was @plugin_enabled
         | 
| 3251 | 
            +
              ensure_type(:@plugins, Array, [])
         | 
| 3252 | 
            +
              ensure_type(:@plugin_commands, Hash, {})
         | 
| 3253 | 
            +
              ensure_type(:@validation_rules, Array, [])
         | 
| 3254 | 
            +
              ensure_type(:@completion_weights, Hash, {})
         | 
| 3255 | 
            +
              ensure_type(:@recording, Hash, {active: false, name: nil, commands: []})
         | 
| 3256 | 
            +
              ensure_type(:@recordings, Hash, {})
         | 
| 3257 | 
            +
             | 
| 3211 3258 | 
             
              @completion_limit ||= 10
         | 
| 3212 3259 | 
             
              @completion_case_sensitive ||= false
         | 
| 3213 3260 | 
             
              @completion_show_descriptions ||= false
         | 
| 3214 3261 | 
             
              @completion_fuzzy ||= true
         | 
| 3215 | 
            -
              @cmd_frequency ||= {}
         | 
| 3216 | 
            -
              @cmd_stats ||= {}
         | 
| 3217 | 
            -
              @bookmarks ||= {}
         | 
| 3218 | 
            -
              @defuns ||= {}
         | 
| 3219 | 
            -
              @switch_cache ||= {}
         | 
| 3220 | 
            -
              @switch_cache_time ||= {}
         | 
| 3221 3262 | 
             
              @history_dedup ||= 'smart'
         | 
| 3222 3263 | 
             
              @session_autosave ||= 0
         | 
| 3223 3264 | 
             
              @auto_correct ||= false
         | 
| 3224 3265 | 
             
              @slow_command_threshold ||= 0
         | 
| 3225 | 
            -
              @plugin_enabled ||= []
         | 
| 3226 | 
            -
              @plugins ||= []
         | 
| 3227 | 
            -
              @plugin_commands ||= {}
         | 
| 3228 | 
            -
              @validation_rules ||= []
         | 
| 3229 | 
            -
              @completion_weights ||= {}
         | 
| 3230 3266 | 
             
              @completion_learning = true if @completion_learning.nil?
         | 
| 3231 | 
            -
             | 
| 3232 | 
            -
              @recordings ||= {}
         | 
| 3267 | 
            +
             | 
| 3233 3268 | 
             
              puts "Loaded with default configuration."
         | 
| 3234 3269 | 
             
            end
         | 
| 3235 3270 |  | 
    
        metadata
    CHANGED
    
    | @@ -1,20 +1,20 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: ruby-shell
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 3.4. | 
| 4 | 
            +
              version: 3.4.9
         | 
| 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- | 
| 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. | 
| 16 | 
            -
               | 
| 17 | 
            -
               | 
| 15 | 
            +
              v3.4.9: Improved :calc with Math sandbox for safer evaluation, better error messages
         | 
| 16 | 
            +
              (division by zero, unknown functions, syntax errors). Suggested by havenwood from
         | 
| 17 | 
            +
              #ruby IRC!'
         | 
| 18 18 | 
             
            email: g@isene.com
         | 
| 19 19 | 
             
            executables:
         | 
| 20 20 | 
             
            - rsh
         |