stockr 0.0.1 → 0.1.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/Gemfile +4 -6
- data/Gemfile.lock +6 -1
- data/README.rdoc +67 -0
- data/VERSION +1 -1
- data/lib/stockr/assets/bundle.js +1554 -0
- data/lib/stockr/part.rb +19 -4
- data/lib/stockr/store.rb +1 -1
- data/lib/stockr/web.rb +62 -119
- metadata +27 -14
- data/lib/stockr/assets/knockout.js +0 -63
data/lib/stockr/part.rb
CHANGED
@@ -12,6 +12,7 @@ module Stockr
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def save
|
15
|
+
return false unless name && !name.empty?
|
15
16
|
Store.write(name, { :qty => qty, :price => price })
|
16
17
|
end
|
17
18
|
|
@@ -30,21 +31,34 @@ module Stockr
|
|
30
31
|
end
|
31
32
|
|
32
33
|
def price=(pr)
|
33
|
-
|
34
|
+
# BigDecimal.new()
|
35
|
+
@price = pr.kind_of?(Numeric) ? pr.to_f : pr.gsub(",", ".").to_f
|
34
36
|
end
|
35
37
|
|
36
|
-
def
|
38
|
+
def price_total
|
39
|
+
price * qty
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_json
|
43
|
+
"{name: '#{name}', qty: '#{qty}', price: '%.3f', total_price: '%.3f'}" % [price, price_total]
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.find_or_create(q, name, pr=0, incr = false)
|
37
47
|
part = search(name, true) || new(name)
|
38
|
-
part.qty += q.to_i
|
48
|
+
incr ? part.qty += q.to_i : part.qty = q.to_i
|
39
49
|
part.price = pr
|
40
50
|
part.save
|
41
51
|
part
|
42
52
|
end
|
43
53
|
|
54
|
+
def self.create_or_increment(q, name, pr=0)
|
55
|
+
find_or_create(q, name, pr, true)
|
56
|
+
end
|
57
|
+
|
44
58
|
def self.search(txt, exact = false)
|
45
59
|
if res = Store.find(exact ? txt : "*#{txt}*")
|
46
60
|
objs = res.map do |k, r|
|
47
|
-
new(k, r["qty"])
|
61
|
+
new(k, r["qty"], r["price"])
|
48
62
|
end
|
49
63
|
exact ? objs[0] : objs # FIXME: better way?
|
50
64
|
else
|
@@ -62,6 +76,7 @@ module Stockr
|
|
62
76
|
all.select { |p| p.qty <= 0 }
|
63
77
|
end
|
64
78
|
|
79
|
+
|
65
80
|
end
|
66
81
|
|
67
82
|
|
data/lib/stockr/store.rb
CHANGED
data/lib/stockr/web.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
|
+
|
1
2
|
require "sinatra"
|
3
|
+
unless Module.const_defined?("Stockr")
|
4
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__) + "/../"))
|
5
|
+
require "stockr"
|
6
|
+
end
|
2
7
|
include Stockr
|
3
|
-
# unless const_defined?("Stockr")
|
4
8
|
|
5
|
-
# require "stockr"
|
6
|
-
|
7
|
-
get '/hi' do
|
8
|
-
"Hello World!"
|
9
|
-
end
|
10
9
|
|
11
10
|
get '/' do
|
12
|
-
|
11
|
+
parts = Part.all
|
12
|
+
@parts = parts.map(&:to_json)
|
13
|
+
@sum = parts.reduce(0) { |n, p| n += p.price_total }
|
14
|
+
p @parts
|
13
15
|
erb <<INDEX
|
14
16
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
15
17
|
<html class="cufon-active cufon-ready"><head>
|
@@ -17,13 +19,10 @@ get '/' do
|
|
17
19
|
|
18
20
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
19
21
|
<title>Stockr : My Stock</title>
|
20
|
-
|
21
|
-
<!--[if lte IE 7]><link rel="stylesheet" type="text/css" href="../css/ie6ie7.css" /><![endif]-->
|
22
|
-
<!--[if lte IE 6]><link rel="stylesheet" type="text/css" href="../css/ie6.css" /><![endif]-->
|
23
|
-
<script type="text/javascript" src="knockout.js"></script>
|
22
|
+
<script type="text/javascript" src="bundle.js"></script>
|
24
23
|
|
25
|
-
|
26
|
-
/*
|
24
|
+
<style type="text/css">
|
25
|
+
/* CSS ************************************************************************/
|
27
26
|
.content { font-size: 1.1em !important; }
|
28
27
|
.content p + ul { margin-top: -0.8em; }
|
29
28
|
.sticker .content h1 { font-size: 1.6em; margin: 0.4em 0 0.4em 0; }
|
@@ -34,23 +33,6 @@ get '/' do
|
|
34
33
|
|
35
34
|
/* Basics */
|
36
35
|
a { text-decoration: none; }
|
37
|
-
code { font-family: Consolas, Monaco, "Courier New", mono-space, monospace !important; }
|
38
|
-
.content .syntaxhighlighter table, .content .syntaxhighlighter td { border-width: 0; }
|
39
|
-
.content .syntaxhighlighter table { margin-bottom: 0; }
|
40
|
-
.syntaxhighlighter {
|
41
|
-
width: 680px; overflow-x: auto; margin-bottom: 1.8em;
|
42
|
-
-moz-border-radius: 0.5em; -webkit-border-radius: 0.5em; border-radius: 0.5em;
|
43
|
-
}
|
44
|
-
.syntaxhighlighter .line {
|
45
|
-
white-space: pre !important;
|
46
|
-
line-height: 1.2em;
|
47
|
-
}
|
48
|
-
.syntaxhighlighter code {
|
49
|
-
white-space: pre !important;
|
50
|
-
}
|
51
|
-
.syntaxhighlighter.ie {
|
52
|
-
overflow-y: hidden;
|
53
|
-
}
|
54
36
|
|
55
37
|
.center { text-align: center }
|
56
38
|
.left { text-align: left }
|
@@ -70,19 +52,11 @@ code { font-family: Consolas, Monaco, "Courier New", mono-space, monospace !impo
|
|
70
52
|
.inline { display: inline; }
|
71
53
|
.cursor { cursor: pointer }
|
72
54
|
|
73
|
-
|
74
|
-
background-image: url(../img/checkIcon.gif); background-repeat: no-repeat; background-position: 0px 6px;
|
75
|
-
margin-left: -0.5em; padding-left: 2em; line-height: 2em; margin-bottom: 0.3em;
|
76
|
-
}
|
77
|
-
|
78
|
-
li p.smallprint { margin-top: -0.25em; line-height: 1.4em; font-size: 0.9em; margin-bottom: 0.9em; font-style: italic; color: #444; }
|
79
|
-
|
80
|
-
ul.stickerList li { margin: 0.5em 0 0.9em 0; }
|
81
|
-
ul.stickerList li p.smallprint { margin-top: 0.1em; }
|
55
|
+
.small { margin-top: -0.25em; line-height: 1.4em; font-size: 0.8em; margin-bottom: 0.9em; font-style: italic; color: #444; }
|
82
56
|
|
83
57
|
/* Page */
|
84
58
|
#wrapper {margin: 0 auto; width: 982px; }
|
85
|
-
html { background: #d05400
|
59
|
+
html { background: #d05400 no-repeat top center; }
|
86
60
|
body { font-family: arial; font-size: 14px; }
|
87
61
|
.sticker {
|
88
62
|
background-color: white; padding: 1.25em 1.45em 1.25em 1.55em; margin: 0.5em 0 3em 0; -moz-border-radius: 1em; -webkit-border-radius: 1em; border-radius: 1em;
|
@@ -96,14 +70,10 @@ body { font-family: arial; font-size: 14px; }
|
|
96
70
|
border-top-right-radius: 1em; border-top-left-radius: 1em;
|
97
71
|
}
|
98
72
|
|
99
|
-
.engraved {
|
100
|
-
color: #350808;
|
101
|
-
text-shadow: rgba(253, 204, 197, 0.4) 1px 1px 0px;
|
102
|
-
}
|
103
|
-
|
73
|
+
.engraved { color: #350808; text-shadow: rgba(253, 204, 197, 0.4) 1px 1px 0px;}
|
104
74
|
.vspace { height: 2em;}
|
105
75
|
|
106
|
-
.liveExample { padding: 1em; background-color: #EEEEDD; border: 1px solid #CCC; max-width:
|
76
|
+
.liveExample { padding: 1em; background-color: #EEEEDD; border: 1px solid #CCC; max-width: 98%; }
|
107
77
|
.liveExample input { font-family: Arial; }
|
108
78
|
.liveExample b { font-weight: bold; }
|
109
79
|
.liveExample p { margin-top: 0.9em; margin-bottom: 0.9em; }
|
@@ -123,47 +93,20 @@ body { font-family: arial; font-size: 14px; }
|
|
123
93
|
/* Intro */
|
124
94
|
#introBadges li { width: 215px; float:left; text-align: center; padding: 0 0.5em 0 0.5em; color: #555; margin-bottom: 0.5em; }
|
125
95
|
|
126
|
-
/* Homepage */
|
127
|
-
#slogan {
|
128
|
-
float:right; width: 17em;
|
129
|
-
padding-left: 1.4em;
|
130
|
-
background: url(../img/vertical-bar.png) no-repeat;
|
131
|
-
font-size: 20px;
|
132
|
-
margin-bottom: 0.6em;
|
133
|
-
}
|
134
96
|
|
135
|
-
|
136
|
-
|
137
|
-
width: 173px; height: 51px;
|
138
|
-
display: block;
|
139
|
-
margin-top: 0.6em;
|
140
|
-
}
|
141
|
-
.download-button p {
|
142
|
-
color: #005500;
|
143
|
-
font-size: 17px;
|
144
|
-
padding: 0.6em 0 0 9px;
|
145
|
-
}
|
146
|
-
.download-button p.smallprint {
|
147
|
-
font-size: 12px;
|
148
|
-
padding: 0.1em 0 0 11px;
|
149
|
-
}
|
150
|
-
.download-button:hover p { text-decoration: underline; }
|
97
|
+
/* Footer */
|
98
|
+
#page-footer { padding: 15px; text-align: right; }
|
151
99
|
|
100
|
+
.liveExample table, .liveExample td, .liveExample th { padding: 0.2em; border-width: 0; }
|
101
|
+
.liveExample td input { width: 13em; }
|
102
|
+
tr { vertical-align: top; }
|
103
|
+
.liveExample input.error { border: 1px solid red; background-color: #FDC; }
|
104
|
+
.liveExample label.error { display: block; color: Red; font-size: 0.8em; }
|
152
105
|
|
153
|
-
|
154
|
-
.homepageExample .liveExample { padding: 0.5em 1em 0.5em 1.3em; }
|
155
|
-
.homepageExample .liveExample button { padding: 0.2em 0.6em; margin-left: 0.5em; }
|
156
|
-
.homepageExample p { margin: 1.3em 0 0.8em 0; }
|
106
|
+
/* CSS ****************************************************************************/
|
157
107
|
|
158
|
-
|
159
|
-
#page-footer { padding: 15px; text-align: right; }
|
108
|
+
</style>
|
160
109
|
|
161
|
-
.liveExample table, .liveExample td, .liveExample th { padding: 0.2em; border-width: 0; }
|
162
|
-
.liveExample td input { width: 13em; }
|
163
|
-
tr { vertical-align: top; }
|
164
|
-
.liveExample input.error { border: 1px solid red; background-color: #FDC; }
|
165
|
-
.liveExample label.error { display: block; color: Red; font-size: 0.8em; }
|
166
|
-
</style>
|
167
110
|
|
168
111
|
</head><body>
|
169
112
|
<div id="wrapper">
|
@@ -172,14 +115,14 @@ body { font-family: arial; font-size: 14px; }
|
|
172
115
|
<div class="sticker">
|
173
116
|
<div class="content">
|
174
117
|
|
175
|
-
|
176
|
-
|
177
|
-
<form action="/
|
178
|
-
<p>You have asked for <span data-bind="text: parts().length">2</span> part(s)</p>
|
118
|
+
<h2>My Stock - <%= Time.now %> </h2>
|
119
|
+
<div class="liveExample">
|
120
|
+
<form action="/up">
|
179
121
|
<table data-bind="visible: parts().length > 0">
|
180
122
|
<thead>
|
181
123
|
<tr>
|
182
|
-
<th>
|
124
|
+
<th>Qty</th>
|
125
|
+
<th>Name</th>
|
183
126
|
<th>Price</th>
|
184
127
|
<th>
|
185
128
|
</th></tr>
|
@@ -189,27 +132,27 @@ body { font-family: arial; font-size: 14px; }
|
|
189
132
|
|
190
133
|
<button data-bind="click: addPart">Add Part</button>
|
191
134
|
<button data-bind="enable: parts().length > 0" type="submit">Submit</button>
|
135
|
+
<p>We got <span data-bind="text: parts().length">2</span> part(s). $ <%= @sum %> </p>
|
192
136
|
</form>
|
193
137
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
138
|
+
<script type="text/html" id="partRowTemplate">
|
139
|
+
<tr>
|
140
|
+
<td><input class="required number" data-bind="value: qty, uniqueName: true"/></td>
|
141
|
+
<td><input class="required" data-bind="value: name, uniqueName: true"/></td>
|
142
|
+
<td><input class="number" data-bind="value: price, uniqueName: true"/></td>
|
143
|
+
<td><span class="small" data-bind="text: total_price"></span></td>
|
144
|
+
<td><a href="#" data-bind="click: function() { viewModel.removePart($data) }">Delete</a></td>
|
145
|
+
</tr>
|
146
|
+
</script>
|
201
147
|
|
202
148
|
|
203
149
|
<script type="text/javascript">
|
204
150
|
/*<![CDATA[*/
|
205
151
|
var viewModel = {
|
206
|
-
parts: ko.observableArray([
|
207
|
-
<!-- { name: "Tall Hat", price: "39.95" }, -->
|
208
|
-
<!-- { name: "Long Cloak", price: "120.00" } -->
|
209
|
-
]),
|
152
|
+
parts: ko.observableArray([<%= @parts.join(',') %>]),
|
210
153
|
|
211
154
|
addPart: function () {
|
212
|
-
this.parts.push({ name: "", price: "" });
|
155
|
+
this.parts.push({ qty: "", name: "", price: "", total_price: "" });
|
213
156
|
},
|
214
157
|
|
215
158
|
removePart: function (part) {
|
@@ -217,8 +160,8 @@ body { font-family: arial; font-size: 14px; }
|
|
217
160
|
},
|
218
161
|
|
219
162
|
save: function (form) {
|
220
|
-
|
221
|
-
|
163
|
+
//lert("Could now transmit to server: " + ko.utils.stringifyJson(this.parts));
|
164
|
+
ko.utils.postJson($("form")[0], this.parts);
|
222
165
|
}
|
223
166
|
};
|
224
167
|
|
@@ -248,18 +191,7 @@ body { font-family: arial; font-size: 14px; }
|
|
248
191
|
|
249
192
|
|
250
193
|
<br><br><br><br>
|
251
|
-
|
252
|
-
|
253
|
-
%table
|
254
|
-
%tr
|
255
|
-
%th Name
|
256
|
-
%th Qty
|
257
|
-
%th Price
|
258
|
-
- for pr in @parts
|
259
|
-
%tr
|
260
|
-
%td= pr.name
|
261
|
-
%td= pr.qty
|
262
|
-
%td= pr.price
|
194
|
+
|
263
195
|
|
264
196
|
Total:
|
265
197
|
|
@@ -270,13 +202,10 @@ get '/new' do
|
|
270
202
|
haml :new
|
271
203
|
end
|
272
204
|
|
273
|
-
get '/
|
274
|
-
File.open(File.dirname(__FILE__) + "/assets/
|
205
|
+
get '/bundle.js' do
|
206
|
+
File.open(File.dirname(__FILE__) + "/assets/bundle.js")
|
275
207
|
end
|
276
208
|
|
277
|
-
get '/up' do
|
278
|
-
"..."
|
279
|
-
end
|
280
209
|
|
281
210
|
get '/:id' do
|
282
211
|
@part = Part.find(params[:id])
|
@@ -287,6 +216,20 @@ get '/:id' do
|
|
287
216
|
end
|
288
217
|
end
|
289
218
|
|
219
|
+
|
220
|
+
post '/up' do
|
221
|
+
params.each do |id, data|
|
222
|
+
data.gsub!(/\\|\"/, "")
|
223
|
+
# just to not require json and play
|
224
|
+
attrs = [:qty, :name, :price].map { |a| data.match(/\{?\s?(#{a})\s?:\s?(\w*)}?/)[2] }
|
225
|
+
p attrs
|
226
|
+
Part.find_or_create(*attrs)
|
227
|
+
end
|
228
|
+
"..."
|
229
|
+
redirect '/'
|
230
|
+
end
|
231
|
+
|
232
|
+
|
290
233
|
post '/' do
|
291
234
|
@part = Part.new(:distance => params[:distance], :minutes => params[:minutes])
|
292
235
|
if @part.save
|
@@ -296,5 +239,5 @@ post '/' do
|
|
296
239
|
end
|
297
240
|
end
|
298
241
|
|
299
|
-
Sinatra::Application.run!
|
242
|
+
# Sinatra::Application.run!
|
300
243
|
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
- 0
|
8
7
|
- 1
|
9
|
-
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Marcos Piccinini
|
@@ -31,8 +31,21 @@ dependencies:
|
|
31
31
|
prerelease: false
|
32
32
|
version_requirements: *id001
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
|
-
name:
|
34
|
+
name: sinatra
|
35
35
|
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
none: false
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
segments:
|
41
|
+
- 0
|
42
|
+
version: "0"
|
43
|
+
type: :development
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: *id002
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
36
49
|
none: false
|
37
50
|
requirements:
|
38
51
|
- - ~>
|
@@ -44,10 +57,10 @@ dependencies:
|
|
44
57
|
version: 2.1.0
|
45
58
|
type: :development
|
46
59
|
prerelease: false
|
47
|
-
version_requirements: *
|
60
|
+
version_requirements: *id003
|
48
61
|
- !ruby/object:Gem::Dependency
|
49
62
|
name: bundler
|
50
|
-
requirement: &
|
63
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
51
64
|
none: false
|
52
65
|
requirements:
|
53
66
|
- - ~>
|
@@ -59,10 +72,10 @@ dependencies:
|
|
59
72
|
version: 1.0.0
|
60
73
|
type: :development
|
61
74
|
prerelease: false
|
62
|
-
version_requirements: *
|
75
|
+
version_requirements: *id004
|
63
76
|
- !ruby/object:Gem::Dependency
|
64
77
|
name: jeweler
|
65
|
-
requirement: &
|
78
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
66
79
|
none: false
|
67
80
|
requirements:
|
68
81
|
- - ~>
|
@@ -74,10 +87,10 @@ dependencies:
|
|
74
87
|
version: 1.5.1
|
75
88
|
type: :development
|
76
89
|
prerelease: false
|
77
|
-
version_requirements: *
|
90
|
+
version_requirements: *id005
|
78
91
|
- !ruby/object:Gem::Dependency
|
79
92
|
name: rcov
|
80
|
-
requirement: &
|
93
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
81
94
|
none: false
|
82
95
|
requirements:
|
83
96
|
- - ">="
|
@@ -87,10 +100,10 @@ dependencies:
|
|
87
100
|
version: "0"
|
88
101
|
type: :development
|
89
102
|
prerelease: false
|
90
|
-
version_requirements: *
|
103
|
+
version_requirements: *id006
|
91
104
|
- !ruby/object:Gem::Dependency
|
92
105
|
name: redis
|
93
|
-
requirement: &
|
106
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
94
107
|
none: false
|
95
108
|
requirements:
|
96
109
|
- - ">="
|
@@ -100,7 +113,7 @@ dependencies:
|
|
100
113
|
version: "0"
|
101
114
|
type: :runtime
|
102
115
|
prerelease: false
|
103
|
-
version_requirements: *
|
116
|
+
version_requirements: *id007
|
104
117
|
description: Help keep track of stuff (good for electronics)
|
105
118
|
email: x@nofxx.com
|
106
119
|
executables:
|
@@ -121,7 +134,7 @@ files:
|
|
121
134
|
- VERSION
|
122
135
|
- bin/stockr
|
123
136
|
- lib/stockr.rb
|
124
|
-
- lib/stockr/assets/
|
137
|
+
- lib/stockr/assets/bundle.js
|
125
138
|
- lib/stockr/export.rb
|
126
139
|
- lib/stockr/part.rb
|
127
140
|
- lib/stockr/store.rb
|
@@ -143,7 +156,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
143
156
|
requirements:
|
144
157
|
- - ">="
|
145
158
|
- !ruby/object:Gem::Version
|
146
|
-
hash:
|
159
|
+
hash: -709536225112595033
|
147
160
|
segments:
|
148
161
|
- 0
|
149
162
|
version: "0"
|