tofu 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.
@@ -0,0 +1,206 @@
1
+ require 'tofu'
2
+ require 'rinda/tuplespace'
3
+ require 'singleton'
4
+ require 'digest/md5'
5
+ require 'enumerator'
6
+
7
+ class Njet
8
+ def initialize(value)
9
+ @value = value
10
+ end
11
+
12
+ def ===(other)
13
+ @value != other
14
+ end
15
+ end
16
+
17
+ class Store
18
+ include Singleton
19
+
20
+ def initialize
21
+ @tree = []
22
+ @ts = Rinda::TupleSpace.new(3)
23
+ @ts.write([:latest, 0])
24
+ end
25
+ attr_reader :tree
26
+
27
+ def each_slice(n, &blk)
28
+ _, key = @ts.take([:latest, nil])
29
+ @tree.each_slice(n, &blk)
30
+ nil
31
+ ensure
32
+ @ts.write([:latest, key])
33
+ end
34
+
35
+ def headline
36
+ _, value = @tree.first
37
+ value ? value[0] : nil
38
+ end
39
+
40
+ def via_drb
41
+ 'drb ' + Thread.current[:DRb]['client'].stream.peeraddr[2] rescue nil
42
+ end
43
+
44
+ def via_cgi(context)
45
+ context.req.peeraddr[2] rescue nil
46
+ end
47
+
48
+ def latest
49
+ @ts.read([:latest, nil])[1]
50
+ end
51
+
52
+ def wait(key)
53
+ @ts.read([:latest, Njet.new(key)], 10) rescue nil
54
+ end
55
+
56
+ def import_string(str)
57
+ str.dup.force_encoding('utf-8')
58
+ rescue
59
+ "(?)"
60
+ end
61
+
62
+ def add(str, context=nil)
63
+ str = import_string(str)
64
+ from = context ? via_cgi(context) : via_drb
65
+ from ||= 'local'
66
+ @ts.take([:latest, nil])
67
+ begin
68
+ key = -10 * Time.now.to_f
69
+ @tree.unshift([key, [str, from]])
70
+ str
71
+ ensure
72
+ @ts.write([:latest, key.to_i])
73
+ end
74
+ end
75
+ end
76
+
77
+ class KotoSession < Tofu::Session
78
+ def initialize(bartender, hint=nil)
79
+ super
80
+ @content = Store.instance
81
+ @base = BaseTofu.new(self)
82
+ @age = nil
83
+ @interval = 5000
84
+ end
85
+ attr_reader :interval
86
+ attr_reader :content
87
+
88
+ def expires
89
+ Time.now + 60
90
+ end
91
+
92
+ def do_GET(context)
93
+ context.res_header('pragma', 'no-cache')
94
+ context.res_header('cache-control', 'no-cache')
95
+ context.res_header('expires', 'Thu, 01 Dec 1994 16:00:00 GMT')
96
+ dispatch_event(context)
97
+ do_inner_html(context)
98
+ reset_age
99
+ context.res_header('content-type', 'text/html; charset=utf-8')
100
+ context.res_body(@base.to_html(context))
101
+ end
102
+
103
+ def wait
104
+ @content.wait(@age) if @age
105
+ @age = @content.latest
106
+ end
107
+
108
+ def lookup_view(context)
109
+ @base
110
+ end
111
+
112
+ def reset_age
113
+ @age = nil
114
+ end
115
+
116
+ def headline
117
+ @content.headline || 'Koya'
118
+ end
119
+ end
120
+
121
+ class BaseTofu < Tofu::Tofu
122
+ set_erb('base.erb')
123
+
124
+ def initialize(session)
125
+ super(session)
126
+ @enter = EnterTofu.new(session)
127
+ @list = ListTofu.new(session)
128
+ end
129
+ end
130
+
131
+ class EnterTofu < Tofu::Tofu
132
+ set_erb('enter.erb')
133
+
134
+ def do_enter(context, params)
135
+ str ,= params['str']
136
+ str = '(nil)' if (str.nil? || str.empty?)
137
+ @session.content.add(str, context)
138
+ @session.reset_age
139
+ end
140
+
141
+ def tofu_id
142
+ 'enter'
143
+ end
144
+ end
145
+
146
+ class ListTofu < Tofu::Tofu
147
+ set_erb('list.erb')
148
+
149
+ Color = Hash.new do |h, k|
150
+ md5 = Digest::MD5.new
151
+ md5 << k.to_s
152
+ r = 0b01111111 & md5.digest[0].unpack("c").first
153
+ g = 0b01111111 & md5.digest[1].unpack("c").first
154
+ b = 0b01111111 & md5.digest[2].unpack("c").first
155
+ h[k] = sprintf("#%02x%02x%02x", r, g, b)
156
+ end
157
+
158
+ def initialize(session)
159
+ super(session)
160
+ @content = session.content
161
+ @color = Color
162
+ end
163
+
164
+ def to_inner_html(context)
165
+ @session.wait
166
+ to_html(context)
167
+ end
168
+
169
+ def group_header(from, time)
170
+ from + ' @ ' + time.strftime("%H:%M")
171
+ end
172
+ end
173
+
174
+ class MyTofulet < Tofu::CGITofulet
175
+ def [](key)
176
+ Store.instance if key == 'store'
177
+ end
178
+ end
179
+
180
+ WEBrick::Daemon.start unless $DEBUG
181
+ tofu = Tofu::Bartender.new(KotoSession, 'koto_8082')
182
+ s = WEBrick::HTTPServer.new(:Port => 8082)
183
+ s.mount("/", Tofu::Tofulet, tofu)
184
+ s.start
185
+
186
+ =begin
187
+ # dRuby & CGI style
188
+ unless $DEBUG
189
+ exit!(0) if fork
190
+ Process.setsid
191
+ exit!(0) if fork
192
+ end
193
+
194
+ uri = ARGV.shift || 'druby://localhost:54322'
195
+ tofu = Tofu::Bartender.new(KotoSession, 'koto_' + uri.split(':').last)
196
+ DRb.start_service(uri, MyTofulet.new(tofu))
197
+
198
+ unless $DEBUG
199
+ STDIN.reopen('/dev/null')
200
+ STDOUT.reopen('/dev/null', 'w')
201
+ STDERR.reopen('/dev/null', 'w')
202
+ end
203
+
204
+ DRb.thread.join
205
+ =end
206
+
@@ -0,0 +1,20 @@
1
+ <%= update_after(@session.interval, context)%>
2
+ <%= on_update_script('document.title = "' + h(@session.headline) + '"') %>
3
+ <ul>
4
+ <%
5
+ last_group = nil
6
+ @content.each_slice(30) do |ary|
7
+ ary.each do |k, v|
8
+ time = Time.at(-0.1 * k)
9
+ str, from = v
10
+ group = group_header(from, time)
11
+ if group != last_group %>
12
+ <li class="group" style="color:<%= @color[from] %>"><%=h group %></li>
13
+ <% last_group = group
14
+ end
15
+ %> <li><%=h str %></li><%
16
+ end
17
+ break
18
+ end
19
+ %>
20
+ </ul>
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tofu
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Masatoshi SEKI
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-01-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description: tiny web-ui framework for plain WEBrick lovers
42
+ email:
43
+ - seki@ruby-lang.org
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - doc/Div.rd
49
+ - doc/request.gif
50
+ - doc/request.obj
51
+ - doc/response.gif
52
+ - doc/response.obj
53
+ - doc/yfd01.gif
54
+ - doc/yfd01.obj
55
+ - doc/yfd02.gif
56
+ - doc/yfd02.obj
57
+ - doc/yfd03.gif
58
+ - doc/yfd03.obj
59
+ - lib/tofu.rb
60
+ - lib/tofu/version.rb
61
+ - sample/koto/base.erb
62
+ - sample/koto/enter.erb
63
+ - sample/koto/koto.rb
64
+ - sample/koto/list.erb
65
+ homepage: https://github.com/seki/Tofu
66
+ licenses:
67
+ - MIT
68
+ metadata: {}
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ requirements: []
84
+ rubyforge_project:
85
+ rubygems_version: 2.5.1
86
+ signing_key:
87
+ specification_version: 4
88
+ summary: tiny web-ui framework for me.
89
+ test_files: []