#!/usr/bin/env ruby # generated by rubinjam v0.7.1 -- https://github.com/grosser/rubinjam module Rubinjam LIBRARIES = { "pru/core_ext/array" => "class Array\n # http://madeofcode.com/posts/74-ruby-core-extension-array-sum\n def sum(method = nil, &block)\n if block_given?\n raise ArgumentError, \"You cannot pass a block and a method!\" if method\n inject(0) { |sum, i| sum + yield(i) }\n elsif method\n inject(0) { |sum, i| sum + i.send(method) }\n else\n inject(0) { |sum, i| sum + i }\n end\n end unless method_defined?(:sum)\n\n def mean(*args, &block)\n sum(*args, &block) / size.to_f\n end unless method_defined?(:mean)\n\n def grouped\n group_by { |x| x }\n end unless method_defined?(:grouped)\n\n def counted\n grouped.sort_by{|d, f| -1 * f.size }.map{|d, f| \"\#{d} : \#{f.size}\" }\n end unless method_defined?(:counted)\nend\n", "pru/version" => "module Pru\n VERSION = \"0.2.1\"\nend\n", "pru" => "require 'pru/core_ext/array'\n\nmodule Pru\n class << self\n def map(io, code)\n String.class_eval <<-RUBY, __FILE__, __LINE__ + 1\n def _pru(i)\n \#{code}\n end\n RUBY\n\n i = 0\n io.each_line do |line|\n i += 1\n line.chomp!\n result = line._pru(i) or next\n\n case result\n when true then yield line\n when Regexp then yield line if line =~ result\n else yield result\n end\n end\n end\n\n def reduce(array, code)\n Array.class_eval <<-RUBY, __FILE__, __LINE__ + 1\n def _pru\n \#{code}\n end\n RUBY\n array._pru\n end\n end\nend\n", "rubinjam/internal" => "module Rubinjam\n ROOT = File.expand_path(\"../\", __FILE__) << \"/rubinjam/\"\n\n class << self\n def normalize_file(file)\n return file unless file.start_with?(\"/\")\n if file.start_with?(ROOT)\n file.sub(ROOT, \"\")\n else\n file.split('/lib/').last\n end\n end\n\n def file_from_nesting(mod, const)\n if file = mod.rubinjam_autload[const]\n return [mod, file]\n end\n\n nesting(mod.name)[1..-1].detect do |mod|\n file = mod.rubinjam_autload[const]\n break [mod, file] if file\n end\n end\n\n # this does not reflect the actual Module.nesting of the caller,\n # but it should be close enough\n def nesting(name)\n nesting = []\n namespace = name.split(\"::\")\n namespace.inject(Object) do |base, n|\n klass = base.const_get(n)\n nesting << klass\n klass\n end\n nesting.reverse\n end\n end\n\n module ModuleAutoloadFix\n def self.included(base)\n base.class_eval do\n def rubinjam_autload\n @rubinjam_autload ||= {}\n end\n\n alias autoload_without_rubinjam autoload\n def autoload(const, file)\n normalized_file = Rubinjam.normalize_file(file)\n if Rubinjam::LIBRARIES[normalized_file]\n rubinjam_autload[const] = normalized_file\n else\n autoload_without_rubinjam(const, file)\n end\n end\n\n alias const_missing_without_rubinjam const_missing\n def const_missing(const)\n # do not load twice / go into infitire loops\n @rubinjam_tried_const_missing ||= {}\n if @rubinjam_tried_const_missing[const]\n return const_missing_without_rubinjam(const)\n end\n @rubinjam_tried_const_missing[const] = true\n\n # try to find autoload in current module or nesting\n nesting, file = Rubinjam.file_from_nesting(self, const)\n if file\n require file\n nesting.const_get(const)\n else\n const_missing_without_rubinjam(const)\n end\n end\n end\n end\n end\n\n module BaseAutoloadFix\n def self.included(base)\n base.class_eval do\n alias autoload_without_rubinjam autoload\n\n def autoload(const, file)\n normalized_file = Rubinjam.normalize_file(file)\n if Rubinjam::LIBRARIES[normalized_file]\n require normalized_file\n else\n autoload_without_rubinjam(const, file)\n end\n end\n end\n end\n end\nend\n\nModule.send(:include, Rubinjam::ModuleAutoloadFix)\ninclude Rubinjam::BaseAutoloadFix\n\ndef require(file)\n normalized_file = Rubinjam.normalize_file(file)\n if code = Rubinjam::LIBRARIES[normalized_file]\n return if code == :loaded\n eval(code, TOPLEVEL_BINDING, \"rubinjam/\#{normalized_file}.rb\")\n Rubinjam::LIBRARIES[normalized_file] = :loaded\n else\n super\n end\nend\n" } end eval(Rubinjam::LIBRARIES.fetch("rubinjam/internal"), TOPLEVEL_BINDING, "rubinjam") #!/usr/bin/env ruby require 'optparse' # enable local usage from cloned repo root = File.expand_path("../..", __FILE__) $LOAD_PATH << "#{root}/lib" if File.exist?("#{root}/Gemfile") require 'pru' usage = nil options = {} OptionParser.new do |opts| opts.banner = <<-BANNER.gsub(/^ /, "") Pipeable Ruby Use ruby in your pipes, forget about grep / sed / awk / wc ... Map works on each line as String Reduce works on all lines as Array (optional or via -r) Usage: something | pru 'map' something | pru 'map' 'reduce' something | pru '' 'reduce' something | pru --reduce 'reduce' Options: BANNER opts.on("-r", "--reduce CODE","reduce via CODE") {|code| options[:reduce] = code } opts.separator '' opts.on('-I', '--libdir DIR', 'Add DIR to load path') { |dir| $LOAD_PATH << dir } opts.on('--require LIB', 'Require LIB (also comma-separated)') { |lib| lib.split(',').each{|l| require l } } opts.on('-i', '--inplace-edit FILE', 'Edit FILE inplace') { |file| options[:file] = file } opts.separator '' opts.on("-h", "--help","Show this.") { puts opts; exit } opts.on('-v', '--version','Show Version'){ require 'pru/version'; puts Pru::VERSION; exit} usage = opts end.parse! if ARGV.empty? && options.empty? # no arguments -> show usage puts usage exit end abort "Too many arguments, see --help" if ARGV.size > 2 map, reduce = ARGV reduce ||= options[:reduce] map = 'true' if !map || map.empty? if options[:file] output_lines = [] input = File.read(options[:file]) newline = input[/\r\n|\r|\n/] trailing_newline = (input =~ /#{newline}\Z/) else input = $stdin end collector = lambda do |line| if output_lines output_lines << line else begin puts(line) rescue Errno::EPIPE exit 0 end end end if reduce results = [] Pru.map(input, map) { |out| results << out } collector.call Pru.reduce(results, reduce) else Pru.map(input, map) { |out| collector.call out } end if options[:file] content = output_lines.join(newline) content << newline if trailing_newline File.write options[:file], content end