pyradise 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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