pyradise 0.2.1 → 0.3.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.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.1
1
+ 0.3.0
data/bin/pyradise CHANGED
@@ -15,7 +15,6 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
15
15
  require 'pyradise'
16
16
  include Pyradise
17
17
 
18
- OPTIONS = {}
19
18
  MANDATORY_OPTIONS = %w( )
20
19
 
21
20
  parser = OptionParser.new do |opts|
@@ -26,11 +25,21 @@ Usage: #{File.basename($0)} command [args]
26
25
 
27
26
  Options are:
28
27
 
29
- fetch - Get fresh info
30
- list/search - List and filter items
31
- info/show - More info about an item
28
+ fetch - Start/refresh database.
29
+ list/search - List and filter items
30
+ -o --order - Order by: name, price, store.
31
+ info/show - More info about an item
32
+ clear - Wipe out the database
33
+
34
+ Common usage:
35
+
36
+ pyradise fetch
37
+ " list mb i7 - Searches for Intel i7 mobos.
38
+ " list mem -o name - Searches for 'mem' ordered by name.
39
+ " info <sid> - Show price history of the item.
32
40
 
33
41
  BANNER
42
+ opts.on("-o", "--order ORDER", String, "Table order" ) { |order| Options[:order] = order }
34
43
  opts.separator ""
35
44
  opts.parse!(ARGV)
36
45
  end
@@ -39,5 +48,5 @@ if ARGV.empty?
39
48
  puts parser.banner
40
49
  exit
41
50
  else
42
- Pyradise.run! ARGV, OPTIONS
51
+ Pyradise::Cli.run! ARGV
43
52
  end
@@ -0,0 +1,164 @@
1
+ module Pyradise
2
+ class Cli
3
+
4
+ class << self
5
+ include I18n
6
+
7
+ def run! comm
8
+ if respond_to? comm[0]
9
+ send(*comm)
10
+ else
11
+ puts "Can't do that..."
12
+ exit
13
+ end
14
+ end
15
+
16
+ def fetch
17
+ create from_stores
18
+ end
19
+
20
+ def list(*query)
21
+ p query
22
+ t = Time.now
23
+ w = terminal_size[0]
24
+ s = w - 36
25
+ puts "\n#{t(:search)} #{'"' + green(query.join(" ")) + '"' if query[0]}... #{t(:order)}: #{green(Options[:order])}"
26
+ # puts "_" * w
27
+ puts
28
+ prods = Product.filter(:name.like("%#{query.join("%")}%")).order(Options[:order])
29
+ prods.each_with_index do |prod, i|
30
+ name = prod.name.length > s ? prod.name[0..s] + ".. " : prod.name + " "
31
+ for q in query
32
+ b = i % 2 == 0 ? "\e[0m\e[2m" : "\e[0m\e[0m"
33
+ replaces = name.scan(/#{q}/i).length
34
+ name.gsub!(/#{q}/i, "\e[32m\\0#{b}")
35
+ name += "." until name.length > w - 23
36
+ end
37
+ total_price = prod.price * Options[:rate] * Options[:tax]
38
+ out = sprintf("%-6s | %-6s | %-#{s}s %-3d | R$ %s", prod.store, prod.sid, name, prod.price, yellow(total_price.to_i))
39
+
40
+ puts i % 2 == 0 ? bold(out) : out
41
+ end
42
+ puts "_" * w
43
+ puts red("Total: #{prods.all.length} (#{Time.now - t}s)")
44
+ end
45
+ alias :search :list
46
+
47
+ def info(sid=nil)
48
+ if !sid
49
+ puts red("Use: pyradise view <ID>")
50
+ elsif !prod = Product.filter(:sid => sid.to_i).first
51
+ puts yellow("Product not found.")
52
+ else
53
+ w = terminal_size[0] - 20
54
+ prices = prod.prices
55
+ max = prices.values.max.to_f
56
+ prices.keys.sort.each do |k|
57
+ rel = "=" * (prices[k] / max * w)
58
+ puts "#{Time.at(k).strftime('%M/%d')} #{rel}| #{prices[k]}"
59
+ end
60
+ end
61
+ end
62
+ alias :show :info
63
+
64
+ #
65
+ # Wipe all data
66
+ def clear
67
+ print t(:delete)
68
+ return puts unless read_char =~ /y/
69
+ Product.dataset.delete
70
+ puts "\nDB cleared."
71
+ end
72
+
73
+ private
74
+
75
+ def read_char
76
+ system "stty raw -echo"
77
+ out = STDIN.getc
78
+ RUBY_PLATFORM =~ /1.9/ ? out : out.chr
79
+ ensure
80
+ system "stty -raw echo"
81
+ end
82
+
83
+ #
84
+ # Create records from txt files
85
+ def create txts
86
+ products = []
87
+ for txt in txts
88
+ print "Parsing #{txt[:store]}..."
89
+ c = Product.all.length
90
+ parse(txt[:txt], txt[:delimiter]).each do |t|
91
+ next if t[:price] == 0
92
+ create_product(t, txt[:store].to_s)
93
+ end
94
+ puts "#{Product.all.length - c} #{t(:created)}."
95
+ end
96
+ end
97
+
98
+ def create_product(t, store)
99
+ if prod = Product.filter(:name => t[:name], :store => store).first
100
+ prod.new_price!(t[:price]) if t[:price] != prod.price
101
+ else
102
+ Product.create(t.merge(:store => store))
103
+ end
104
+ rescue => e
105
+ puts "SQLITE Err => #{e}"
106
+ p t[:name]
107
+ puts t.inspect
108
+ end
109
+
110
+ def from_stores
111
+ stores = []
112
+ for store in YAML.load(File.new(File.dirname(__FILE__) + '/../stores.yml'))[:stores]
113
+ data = {}
114
+ data[:store] = store[0]
115
+ data[:delimiter] = store[1][:delimiter]
116
+
117
+ # Open URL
118
+ next unless data[:txt] = fetch_store(store)
119
+
120
+ # Open local file to write
121
+ open("#{HOME}#{store[0]}-#{Time.now.to_i}.txt", "wb") do |dump|
122
+ dump.write(data[:txt].gsub(/\t/, ""))
123
+ end
124
+ puts "Store #{store[0]} dumped."
125
+ stores << data
126
+ end
127
+ stores
128
+ end
129
+
130
+ def fetch_store(store)
131
+ open(store[1][:txt]).read
132
+ rescue => e
133
+ puts "#{store[0]} offline: #{e}.".capitalize
134
+ nil
135
+ end
136
+
137
+ def parse(txt, del)
138
+ products = []
139
+ txt.each_line do |l|
140
+ sid, *info = l.split(del)
141
+ next if info.length < 2
142
+ price = info.delete_at(-1).strip.to_i
143
+ next if price.nil? || price.zero?
144
+ products << { :sid => sid.strip, :name => info.join("").strip.gsub(/\.{2,}/, ""), :price => price }
145
+ end
146
+ products
147
+ end
148
+
149
+ # Get terminal size to fit the table nicely.
150
+ # From highliner.
151
+ def terminal_size
152
+ `stty size`.split.map { |x| x.to_i }.reverse
153
+ end
154
+
155
+ def red(txt); "\e[31m#{txt}\e[0m"; end
156
+ def green(txt); "\e[32m#{txt}\e[0m"; end
157
+ def yellow(txt); "\e[33m#{txt}\e[0m"; end
158
+ def bold(txt); "\e[2m#{txt}\e[0m"; end
159
+ end
160
+
161
+
162
+
163
+ end
164
+ end
@@ -0,0 +1,28 @@
1
+ module Pyradise
2
+ module I18n
3
+ I = {
4
+ :en_us =>
5
+ {
6
+ :search => "Searching for",
7
+ :order => "Ordered by",
8
+ :delete => "About to delete all the records. Sure? [y/N] ",
9
+ :created => "products created"
10
+ },
11
+ :pt_br =>
12
+ {
13
+ :search => "Procurando por",
14
+ :order => "Ordenado por",
15
+ :delete => "Deletar todo o banco? [y/N] ",
16
+ :created => "produtos criados"
17
+ }
18
+
19
+
20
+
21
+ }
22
+
23
+ def t(text)
24
+ I[Options[:lang].to_sym][text.to_sym]
25
+ end
26
+
27
+ end
28
+ end
@@ -1,4 +1,5 @@
1
- class Product < Sequel::Model
1
+ module Pyradise
2
+ class Product < Sequel::Model
2
3
 
3
4
  def before_save
4
5
  phist = { Time.now.to_i => price }
@@ -13,4 +14,5 @@ class Product < Sequel::Model
13
14
  self.update(:prices => Marshal.dump(prices ? prices.merge({Time.now.to_i => np}) : np))
14
15
  end
15
16
 
17
+ end
16
18
  end
data/lib/pyradise.rb CHANGED
@@ -1,145 +1,34 @@
1
- require 'rubygems'
2
1
  require 'open-uri'
3
2
  require 'sequel'
4
3
 
5
- #TODO: def init
6
- HOME = ENV['HOME'] + "/.pyradise"
7
- unless File.exists? HOME
8
- FileUtils.mkdir_p HOME
9
- conf = open(HOME + "/conf.yml", "wb")
10
- conf.write(":rate: 2.0\n:tax: 1.3\n")
11
- conf.close
12
- end
13
-
14
- DB = Sequel.connect("sqlite://#{HOME}/py.sqlite3")
15
- require 'pyradise/product'
16
- # require 'pyradise/stat'
17
-
18
- unless DB.table_exists? :products
19
- require 'pyradise/migrate'
20
- CreatePyradise.apply DB, :up
21
- end
22
-
23
4
  module Pyradise
24
5
 
25
- CONF = YAML.load(File.new(HOME + "/conf.yml"))
26
- RATE = CONF[:rate] || 2.0
27
- TAX = CONF[:tax] || 1.3
28
-
29
- class << self
30
-
31
- def run! comm, opts
32
- if respond_to? comm[0]
33
- send(*comm)
34
- else
35
- puts "Can't do that..."
36
- exit
37
- end
38
- end
39
-
40
- def fetch
41
- create from_stores
42
- end
43
-
44
- def list(*query)
45
- t = Time.now
46
- w = terminal_size[0]
47
- s = w - 35
48
- puts "Searching #{'"' + query[0] + '"' if query[0]}... Order by: #{query[1] || 'name'}"
49
- puts "_" * w
50
- prods = Product.filter(:name.like("%#{query[0]}%")).order(query[1] ? query[1].to_sym : :name)
51
- prods.each_with_index do |prod, i|
52
- name = prod.name.length > s ? prod.name[0..s] + ".." : prod.name
53
- out = sprintf("%-6s | %-5s | %-#{w-38}s %-3d | R$ %d", prod.store, prod.sid, name, prod.price, prod.price * RATE * TAX)
54
- puts i % 2 == 0 ? bold(out) : out
55
- end
56
- puts "_" * w
57
- puts green("Total: #{prods.all.length} (#{Time.now - t}s)")
58
- end
59
- alias :search :list
60
-
61
- def info(sid=nil)
62
- if !sid
63
- puts red("Use: pyradise view <ID>")
64
- elsif !prod = Product.filter(:sid => sid.to_i).first
65
- puts yellow("Product not found.")
66
- else
67
- w = terminal_size[0] - 20
68
- prices = prod.prices
69
- max = prices.values.max.to_f
70
- prices.keys.sort.each do |k|
71
- rel = "=" * (prices[k] / max * w)
72
- puts "#{Time.at(k).strftime('%M/%d')} #{rel}| #{prices[k]}"
73
- end
74
- end
75
- end
76
- alias :show :info
77
-
78
- def clear
79
- Product.dataset.delete
80
- end
81
-
82
- private
83
-
84
- def create txts
85
- products = []
86
- for txt in txts
87
- print "Parsing #{txt[:store]}..."
88
- c = Product.all.length
89
- parse(txt[:txt], txt[:delimiter]).each do |t|
90
- next if t[:price] == 0
91
- create_product(t, txt[:store].to_s)
92
- end
93
- puts "#{Product.all.length - c} products created."
94
- end
95
- end
96
-
97
- def create_product(t, store)
98
- if prod = Product.filter(:name => t[:name], :store => store).first
99
- prod.new_price!(t[:price]) if t[:price] != prod.price
100
- else
101
- Product.create(t.merge(:store => store))
102
- end
103
- rescue => e
104
- puts "SQLITE Err => #{e}, #{t.inspect} - #{store} #{prod}"
105
- end
6
+ HOME = ENV['HOME'] + "/.pyradise"
7
+ #TODO: def init
8
+ DB = Sequel.connect("sqlite://#{HOME}/py.sqlite3")
9
+ def locale
10
+ `locale | grep LANG`.scan(/LANG=(.*)\./)[0][0].downcase rescue "en_us"
11
+ end
106
12
 
107
- def from_stores
108
- stores = []
109
- for store in YAML.load(File.new(File.dirname(__FILE__) + '/stores.yml'))[:stores]
110
- data = {}
111
- data[:store] = store[0]
112
- data[:delimiter] = store[1][:delimiter]
113
- dump = open("#{HOME}#{store[0]}-#{Time.now.to_i}.txt", "wb")
114
- data[:txt] = open(store[1][:txt]).read
115
- dump.write(data[:txt])
116
- dump.close
117
- puts "Store #{store[0]} dumped... "
118
- stores << data
119
- end
120
- stores
121
- end
13
+ unless File.exists? HOME
14
+ FileUtils.mkdir_p HOME
15
+ conf = open(HOME + "/conf.yml", "wb")
16
+ conf.write(":rate: 1.8 # dollar conversion rate\n")
17
+ conf.write(":tax: 1.3 # transport tax\n")
18
+ conf.write(":lang: #{locale} # program language\n")
19
+ conf.close
20
+ end
122
21
 
123
- def parse(txt, del)
124
- products = []
125
- txt.each_line do |l|
126
- sid, *info = l.split(del)
127
- next if info.length < 2
128
- price = info.delete_at(-1).strip.to_i
129
- next if price.nil? || price.zero?
130
- products << { :sid => sid.strip, :name => info.join("").strip.gsub(/\.{2,}/, ""), :price => price }
131
- end
132
- products
133
- end
22
+ # require 'pyradise/stat'
23
+ unless DB.table_exists? :products
24
+ require 'pyradise/migrate'
25
+ CreatePyradise.apply DB, :up
26
+ end
27
+ Defaults = {:rate => 1, :tax => 1.3, :order => :price, :lang => :en_us}
28
+ Options = Defaults.merge(YAML.load(File.new(HOME + "/conf.yml")))
134
29
 
135
- #from highliner
136
- def terminal_size
137
- `stty size`.split.map { |x| x.to_i }.reverse
138
- end
30
+ require 'pyradise/product'
31
+ require 'pyradise/i18n'
32
+ require 'pyradise/cli'
139
33
 
140
- def red(txt); "\e[31m#{txt}\e[0m"; end
141
- def green(txt); "\e[32m#{txt}\e[0m"; end
142
- def yellow(txt); "\e[33m#{txt}\e[0m"; end
143
- def bold(txt); "\e[2m#{txt}\e[0m"; end
144
- end
145
34
  end
data/pyradise.gemspec CHANGED
@@ -1,15 +1,15 @@
1
1
  # Generated by jeweler
2
- # DO NOT EDIT THIS FILE
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{pyradise}
8
- s.version = "0.2.1"
8
+ s.version = "0.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Marcos Piccinini"]
12
- s.date = %q{2009-10-10}
12
+ s.date = %q{2009-12-28}
13
13
  s.default_executable = %q{pyradise}
14
14
  s.email = %q{x@nofxx.com}
15
15
  s.executables = ["pyradise"]
@@ -26,6 +26,8 @@ Gem::Specification.new do |s|
26
26
  "VERSION",
27
27
  "bin/pyradise",
28
28
  "lib/pyradise.rb",
29
+ "lib/pyradise/cli.rb",
30
+ "lib/pyradise/i18n.rb",
29
31
  "lib/pyradise/migrate.rb",
30
32
  "lib/pyradise/product.rb",
31
33
  "lib/stores.yml",
@@ -59,3 +61,4 @@ Gem::Specification.new do |s|
59
61
  s.add_dependency(%q<sequel>, [">= 0"])
60
62
  end
61
63
  end
64
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pyradise
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marcos Piccinini
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-10 00:00:00 -03:00
12
+ date: 2009-12-28 00:00:00 -02:00
13
13
  default_executable: pyradise
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -40,6 +40,8 @@ files:
40
40
  - VERSION
41
41
  - bin/pyradise
42
42
  - lib/pyradise.rb
43
+ - lib/pyradise/cli.rb
44
+ - lib/pyradise/i18n.rb
43
45
  - lib/pyradise/migrate.rb
44
46
  - lib/pyradise/product.rb
45
47
  - lib/stores.yml