Module: RTicker
- Defined in:
- lib/rticker/net.rb,
lib/rticker/tput.rb,
lib/rticker/entry.rb,
lib/rticker/equity.rb,
lib/rticker/future.rb,
lib/rticker/option.rb,
lib/rticker/parser.rb,
lib/rticker/options.rb,
lib/rticker/printer.rb,
lib/rticker/currency.rb,
lib/rticker/separator.rb,
lib/rticker/application.rb
Defined Under Namespace
Classes: Application, Currency, Entry, Equity, Future, Net, Option, Options, Separator
Constant Summary collapse
- DEFAULT_ENTRY_FILE =
"#{ENV['HOME']}/.rticker"
Class Method Summary collapse
-
.parse_entry(entry) ⇒ Object
Parse a raw text entry into an instance of Equity, Future, Currency, Option, or Separator.
-
.read_entry_file(file, context = nil) ⇒ Object
Read raw text entries, line by line, from file.
- .tput(args) ⇒ Object
-
.update_screen(entries, no_color = false, once = false) ⇒ Object
Update the screen with the latest information.
Class Method Details
.parse_entry(entry) ⇒ Object
Parse a raw text entry into an instance of Equity, Future, Currency, Option, or Separator.
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/rticker/parser.rb', line 53 def RTicker.parse_entry (entry) # An entry starting with a dash represents a Separator return Separator.new if entry[0,1] == "-" # An entry beginning with an asterisk represents a bold entry. bold = false if entry[0,1] == "*" bold = true entry = entry[1..-1] # Shift off asterisk end ## Here is a breakdown of the format: ## [sign]symbol[,desc[,purchase_count@purchase_price]] ## Where sign can be a "#" (Future), "!" (Option), "^" (Yahoo Equity), ## or "$" (Currency). Anything else represents a Google Equity. pattern = /^([#!^$])?([^,]+)(?:,([^,]*)(?:,(-?[0-9]+)@([0-9]+\.?[0-9]*))?)?/ match = pattern.match entry sign = match[1] symbol = match[2] # Because description is optional, let's make it clear with a nil that no # description was provided. description = match[3] == "" ? nil : match[3] purchase_count = match[4] purchase_price = match[5] args = [symbol, description, purchase_count.to_f, purchase_price.to_f, bold] case sign when "#" # An entry starting with a hash is a Future. A useful mnemonic is to # think of the "pound" sign and think of lbs of a commodity. return Future.new(*args) when "!" # An entry starting with an exclamation mark is an option contract. return Option.new(*args) when "^" # An entry starting with a caret represents an equity to be fetched # from Yahoo Finance. e = Equity.new(*args) e.source = :yahoo return e when "$" # An entry starting with a dollar sign represents a currency pair. return Currency.new(*args) else # Everthing else is an equity to be fetched from Google Finance (the # default). return Equity.new(*args) end end |
.read_entry_file(file, context = nil) ⇒ Object
Read raw text entries, line by line, from file. Return result as an array of text entries. File “-” represents STDIN.
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/rticker/parser.rb', line 9 def RTicker.read_entry_file (file, context=nil) context ||= Dir.pwd # If this is a relative path, make it absolute according to context if file != "-" and file[0,1] != "/" file = [context, file].join("/") end # If we're not dealing with a readable source then get out of here return [] if file != "-" and not File.readable? file if File.symlink? file # Follow symlinks so that we can honor relative include directives return read_entry_file(Pathname.new(file).realpath.to_s) end entries = [] source = if file == "-" then $stdin else File.open(file) end source.each do |line| line.chomp! case line when /^;/, /^\s*$/ # If this line starts with a semicolon (comment) or only contains # whitespace, ignore it. next when /^@.+/ # If this line starts with an @ sign, then this is an 'include' # directive. Ie, this entry is simply including another entry file. # Eg: @otherfile.txt # This will include another file called otherfile.txt include_file = line[1..-1] context = File.dirname(file) unless file == "-" entries += read_entry_file(include_file, context) else entries << line end end entries end |
.tput(args) ⇒ Object
7 8 9 10 11 12 13 |
# File 'lib/rticker/tput.rb', line 7 def RTicker.tput (args) if $__tput_cache.has_key? args $__tput_cache[args] else $__tput_cache[args] = %x[tput #{args}] end end |
.update_screen(entries, no_color = false, once = false) ⇒ Object
Update the screen with the latest information.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/rticker/printer.rb', line 8 def RTicker.update_screen (entries, no_color=false, once=false) # An interesting side-effect of using unless here is that if no_color is # true, then all of these variables are still created, but set to nil. # So setting no_color effectively turns all of the following variables # into empty strings, turning off terminal manipulation. hide_cursor = tput "civis" unless no_color show_cursor = tput "cnorm" unless no_color bold = tput "bold" unless no_color unbold = tput "sgr0" unless no_color default = tput "sgr0" unless no_color red = tput "setaf 1" unless no_color green = tput "setaf 2" unless no_color blue = tput "setaf 4" unless no_color if not once print %x[clear] print "#{hide_cursor}" end print "#{default}" # Calculate the longest symbol name or description max_length = 0 for entry in entries.select {|e| not e.is_a? Separator} output = entry.description || entry.symbol max_length = [output.size, max_length].max end max_length += 2 # Give a little extra breathing room for entry in entries if entry.is_a? Separator print "___________________________________________\n" next # Skip to the next entry end # Prefer a description over a raw symbol name. Use max_length to left # align the output with extra padding on the right. This lines # everything up nice and neat. output = "%-#{max_length}s" % (entry.description || entry.symbol) output = "#{bold}#{output}#{unbold}" if entry.bold? # If we're still waiting for valid responses from yahoo or google, then # just let the user know that they need to wait. curr_value = entry.curr_value || "please wait..." if entry.is_a? Option curr_value = "#{entry.bid}/#{entry.ask}" if entry.bid end # Does this entry have a start_value? If so, let's calculate the # change in percent. change_string = nil if entry.respond_to? :start_value and not entry.start_value.nil? change = entry.curr_value - entry.start_value change_percent = (change / entry.start_value) * 100 color = (change >= 0 ? "#{green}" : "#{red}") change_string = " (#{color}%+.2f %%%0.2f#{default})" % [change, change_percent] end # If this entry has purchase info, let's calculate profit/loss profit_string = nil if entry.purchase_count != 0 and not entry.curr_value.nil? count = entry.purchase_count price = entry.purchase_price # Options are purchased in multiples of 100 of the contract price count *= 100 if entry.is_a? Option # There is also a price multiplier for futures, but they are # completely different for each contract. So the user will simply # need to enter the correct multiplier when configuring the # purchase_count in the ticker entry. For instance, a contract for # CL, crude light sweet oil, has a multiplier of 1000. Ie, one # contract represents 1000 barrels of oil. So if a contract is # bought, the user should enter a purchase_count of 1000. If the # contract is sold (a short position), the purchase_count should be # -1000. profit_loss = count * entry.curr_value - count * price profit_loss_percent = profit_loss / (count*price) * 100 color = (profit_loss >= 0 ? "#{green}" : "#{red}") profit_string = " = #{color}$%.2f %%%0.2f#{default}" % [profit_loss, profit_loss_percent] end case entry when Equity print "#{output} #{curr_value}#{change_string}#{profit_string}" when Future print "#{output} #{curr_value}#{change_string}#{profit_string}" when Option print "#{output} #{curr_value}#{profit_string}" when Currency print "#{output} #{curr_value}#{profit_string}" end # Let the user know with a blue asterisk if this entry has changed # within the past 5 minutes. if entry.last_changed and (Time.now() - entry.last_changed) <= 5*60 print " #{blue}*#{default}" end print "\n" end # for end |