menilite 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/Rakefile +9 -4
- data/lib/menilite.rb +2 -0
- data/lib/menilite/model.rb +127 -21
- data/lib/menilite/server/activerecord_store.rb +1 -1
- data/lib/menilite/version.rb +1 -1
- data/menilite.gemspec +3 -0
- metadata +44 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ff9db82163232317d82fcbfe864f020e713e3dc
|
4
|
+
data.tar.gz: b4511f2ece8e027dd0f0cac02632e3676d1f1fe3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b18f844aca4213efcd77f13c6598a5b2ed16326849221d221e177d668cd751a34054e358c6c7788c23a3ef484278c4326fefe3a3b29faec3d249e1718d9a7f6b
|
7
|
+
data.tar.gz: 004d4eaeceb5e821e0457aeb4416930cde8e769d04a0a33fe0f61b62919f82834927c2d03387cf787b333addf9e25f09cc4857132e36c0973aa2ef5975f4f639
|
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -1,6 +1,11 @@
|
|
1
|
+
require 'opal'
|
2
|
+
require 'opal-browser'
|
3
|
+
require 'opal/rspec/rake_task'
|
1
4
|
require "bundler/gem_tasks"
|
2
|
-
require "rspec/core/rake_task"
|
3
5
|
|
4
|
-
RSpec::
|
5
|
-
|
6
|
-
|
6
|
+
Opal::RSpec::RakeTask.new(:default) do |server, task|
|
7
|
+
task.pattern = 'spec/opal/**/*_spec.rb'
|
8
|
+
server.append_path File.expand_path('../lib', __FILE__)
|
9
|
+
server.source_map = true
|
10
|
+
server.debug = true
|
11
|
+
end
|
data/lib/menilite.rb
CHANGED
data/lib/menilite/model.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'securerandom'
|
2
2
|
|
3
|
-
|
3
|
+
if RUBY_ENGINE == 'opal'
|
4
4
|
require 'browser/http'
|
5
5
|
require 'opal-parser'
|
6
6
|
end
|
@@ -13,6 +13,9 @@ class String
|
|
13
13
|
end
|
14
14
|
|
15
15
|
module Menilite
|
16
|
+
class ValidationError < StandardError; end;
|
17
|
+
class TypeError < StandardError; end;
|
18
|
+
|
16
19
|
class Model
|
17
20
|
include Menilite::Helper
|
18
21
|
|
@@ -21,15 +24,25 @@ module Menilite
|
|
21
24
|
def initialize(fields = {})
|
22
25
|
self.class.init
|
23
26
|
|
24
|
-
if
|
25
|
-
fields = fields.clone
|
26
|
-
else
|
27
|
+
if server?
|
27
28
|
fields = fields.map{|k,v| [k.to_sym, v] }.to_h
|
29
|
+
end
|
30
|
+
|
31
|
+
@guid = fields.delete(:id) || SecureRandom.uuid
|
32
|
+
|
33
|
+
self.class.field_info.select{|_, i| i.type == :reference}.each do |name, info|
|
34
|
+
fields[:"#{name}_id"] = fields[info.name] if fields.has_key?(info.name)
|
35
|
+
end
|
36
|
+
|
37
|
+
fields.each{|k, v| type_validate(k, v) }
|
38
|
+
fields = fields.map{|k,v| [k, convert_value(self.class.field_info[k].type, v)] }.to_h
|
39
|
+
|
40
|
+
if server?
|
28
41
|
fields.merge!(self.class.privilege_fields)
|
29
42
|
end
|
30
43
|
|
31
44
|
defaults = self.class.field_info.map{|k, d| [d.name, d.params[:default]] if d.params.has_key?(:default) }.compact.to_h
|
32
|
-
|
45
|
+
fields = defaults.merge(fields)
|
33
46
|
@fields = defaults.merge(fields)
|
34
47
|
@listeners = {}
|
35
48
|
end
|
@@ -39,6 +52,7 @@ module Menilite
|
|
39
52
|
end
|
40
53
|
|
41
54
|
def save(&block)
|
55
|
+
self.validate_all
|
42
56
|
self.class.store.save(self, &block)
|
43
57
|
self
|
44
58
|
end
|
@@ -88,8 +102,13 @@ module Menilite
|
|
88
102
|
@action_info ||= {}
|
89
103
|
end
|
90
104
|
|
105
|
+
def validators
|
106
|
+
@validators ||= {}
|
107
|
+
end
|
108
|
+
|
91
109
|
def save(collection, &block)
|
92
110
|
self.init
|
111
|
+
colection.each {|obj| obj.validate_all }
|
93
112
|
self.store.save(collection, &block)
|
94
113
|
end
|
95
114
|
|
@@ -105,7 +124,7 @@ module Menilite
|
|
105
124
|
|
106
125
|
def fetch(filter: {}, order: nil)
|
107
126
|
self.init
|
108
|
-
filter = filter.map{|k, v| type_convert(k, v)
|
127
|
+
filter = filter.map{|k, v| type_convert(k.to_sym, v) }.to_h
|
109
128
|
|
110
129
|
if_server do
|
111
130
|
filter.merge!(privilege_filter)
|
@@ -118,7 +137,7 @@ module Menilite
|
|
118
137
|
end
|
119
138
|
|
120
139
|
def type_convert(key, value)
|
121
|
-
field_info = self.field_info[key
|
140
|
+
field_info = self.field_info[key] || self.field_info[key.to_s.sub(/_id\z/,'').to_sym]
|
122
141
|
raise "no such field #{key} in #{self}" unless field_info
|
123
142
|
converted = case field_info.type
|
124
143
|
when :boolean
|
@@ -152,7 +171,11 @@ module Menilite
|
|
152
171
|
return unless params[:server]
|
153
172
|
end
|
154
173
|
|
155
|
-
|
174
|
+
if type == :reference
|
175
|
+
field_info[:"#{name}_id"] = FieldInfo.new(name, type, params)
|
176
|
+
else
|
177
|
+
field_info[name] = FieldInfo.new(name, type, params)
|
178
|
+
end
|
156
179
|
|
157
180
|
self.instance_eval do
|
158
181
|
if type == :reference
|
@@ -160,6 +183,7 @@ module Menilite
|
|
160
183
|
|
161
184
|
define_method(name) do
|
162
185
|
id = @fields[field_name.to_sym]
|
186
|
+
next nil unless id
|
163
187
|
model_class = Object.const_get(name.to_s.camel_case)
|
164
188
|
model_class[id]
|
165
189
|
end
|
@@ -172,14 +196,18 @@ module Menilite
|
|
172
196
|
end
|
173
197
|
|
174
198
|
define_method(field_name) do
|
175
|
-
@fields[field_name.to_sym]
|
199
|
+
value = @fields[field_name.to_sym]
|
200
|
+
if type.is_a?(Hash) && type.keys.first == :enum
|
201
|
+
value = type[:enum][value]
|
202
|
+
end
|
203
|
+
value
|
176
204
|
end
|
177
205
|
|
178
206
|
define_method(field_name + "=") do |value|
|
179
207
|
unless type_validator(type).call(value, name)
|
180
|
-
raise
|
208
|
+
raise TypeError.new("type error: field_name: #{name}, value: #{value}")
|
181
209
|
end
|
182
|
-
@fields[field_name.to_sym] = value
|
210
|
+
@fields[field_name.to_sym] = convert_value(type, value)
|
183
211
|
handle_event(:change, field_name.to_sym, value)
|
184
212
|
end
|
185
213
|
end
|
@@ -223,6 +251,15 @@ module Menilite
|
|
223
251
|
end
|
224
252
|
end
|
225
253
|
|
254
|
+
def validation(field_name, params = {}, &block)
|
255
|
+
params.each do |k, v|
|
256
|
+
if validator = Validators[k, v]
|
257
|
+
(validators[field_name] ||= []) << validator.new(field_name)
|
258
|
+
end
|
259
|
+
end
|
260
|
+
(validators[field_name] ||= []) << Validator.new(field_name, &block) if block
|
261
|
+
end
|
262
|
+
|
226
263
|
def find(id)
|
227
264
|
self.init
|
228
265
|
|
@@ -280,27 +317,58 @@ module Menilite
|
|
280
317
|
def type_validator(type)
|
281
318
|
case type
|
282
319
|
when :string
|
283
|
-
-> (value, name) { value.is_a?
|
320
|
+
-> (value, name) { value.nil? || value.is_a?(String) }
|
284
321
|
when :int
|
285
|
-
-> (value, name) { value.is_a?
|
322
|
+
-> (value, name) { value.nil? || value.is_a?(Integer) }
|
286
323
|
when :boolean
|
287
|
-
-> (value, name) { value == true || value == false }
|
324
|
+
-> (value, name) { value.nil? || value == true || value == false }
|
288
325
|
when :date
|
289
|
-
-> (value, name) { value.is_a?
|
326
|
+
-> (value, name) { value.nil? || value.is_a?(Date) || value.is_a?(String) }
|
290
327
|
when :time
|
291
|
-
-> (value, name) { value.is_a?
|
328
|
+
-> (value, name) { value.nil? || value.is_a?(Time) }
|
329
|
+
when Hash
|
330
|
+
if type.keys.first == :enum
|
331
|
+
-> (value, name) { value.nil? || value.is_a?(Integer) || type[:enum].include?(value) }
|
332
|
+
else
|
333
|
+
raise TypeError.new("type error")
|
334
|
+
end
|
292
335
|
when :reference
|
293
|
-
-> (value, name) {
|
336
|
+
-> (value, name) { value.nil? || validate_reference(value, name) }
|
337
|
+
else
|
338
|
+
raise TypeError.new("type error. type: #{type.inspect}")
|
294
339
|
end
|
295
340
|
end
|
296
341
|
|
297
|
-
def
|
298
|
-
return false unless value.is_a?
|
342
|
+
def validate_reference(value, name)
|
343
|
+
return false unless value.is_a?(String) || value.is_a?(Menilite::Model)
|
299
344
|
|
300
|
-
model_class = Object.const_get(name.camel_case)
|
345
|
+
model_class = Object.const_get(name.to_s.camel_case)
|
301
346
|
not model_class[value].nil?
|
302
347
|
end
|
303
348
|
|
349
|
+
def type_validate(name, value)
|
350
|
+
field_info = self.class.field_info[name]
|
351
|
+
field_info or raise ArgumentError.new("field '#{name}' is not defind")
|
352
|
+
|
353
|
+
type_validator = type_validator(field_info.type)
|
354
|
+
type_validator.call(value, field_info.name) or raise TypeError.new("type error: field_name: #{field_info.name}, value: #{value}")
|
355
|
+
end
|
356
|
+
|
357
|
+
def validate(name, value)
|
358
|
+
validator = self.class.validators[name]
|
359
|
+
if validator
|
360
|
+
messages = validator.map {|validator| validator.validate(value) }.compact
|
361
|
+
messages.empty? or raise ValidationError.new(messages.join(','))
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
def validate_all
|
366
|
+
self.fields.each do |k, v|
|
367
|
+
type_validate(k, v)
|
368
|
+
validate(k, v)
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
304
372
|
def to_h
|
305
373
|
@fields.merge(id: @guid)
|
306
374
|
end
|
@@ -311,6 +379,18 @@ module Menilite
|
|
311
379
|
|
312
380
|
private
|
313
381
|
|
382
|
+
def convert_value(type, value)
|
383
|
+
if type.is_a?(Hash) && type.keys.first == :enum
|
384
|
+
if value.is_a?(Integer)
|
385
|
+
value
|
386
|
+
else
|
387
|
+
type[:enum].index(value)
|
388
|
+
end
|
389
|
+
else
|
390
|
+
value
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
314
394
|
def get_listeners(event, field_name)
|
315
395
|
@listeners[event].try {|l1| l1[field_name] || [] } || []
|
316
396
|
end
|
@@ -322,11 +402,37 @@ module Menilite
|
|
322
402
|
end
|
323
403
|
|
324
404
|
def resolve_references(key, value)
|
325
|
-
if self.class.field_info.has_key?(key
|
405
|
+
if self.class.field_info.has_key?(key) && self.class.field_info[key].type == :reference
|
326
406
|
["#{key}_id".to_sym, value.id]
|
327
407
|
else
|
328
408
|
[key, value]
|
329
409
|
end
|
330
410
|
end
|
411
|
+
|
412
|
+
class Validator
|
413
|
+
def initialize(name, &block)
|
414
|
+
@proc = block
|
415
|
+
end
|
416
|
+
|
417
|
+
def validate(value)
|
418
|
+
@proc.call(value)
|
419
|
+
end
|
420
|
+
end
|
421
|
+
class PresenceValidator < Validator
|
422
|
+
def initialize(name)
|
423
|
+
super(name) {|value| "#{name} must not be empty" if value.nil? || value == "" }
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
class Validators
|
428
|
+
def self.[](key, value)
|
429
|
+
case key
|
430
|
+
when :presence
|
431
|
+
if value == true
|
432
|
+
PresenceValidator
|
433
|
+
end
|
434
|
+
end
|
435
|
+
end
|
436
|
+
end
|
331
437
|
end
|
332
438
|
end
|
@@ -5,7 +5,7 @@ module Menilite
|
|
5
5
|
def self.create_model(model_class)
|
6
6
|
klass = Class.new(::ActiveRecord::Base) do
|
7
7
|
model_class.field_info.select{|name, field| field.type == :reference }.each do |name, field|
|
8
|
-
belongs_to
|
8
|
+
belongs_to name, primary_key: 'guid', foreign_key: "#{name}_guid", class_name: name.to_s.capitalize
|
9
9
|
#klass.instance_eval { define_method(name + '_id') { send(name + '_guid') } }
|
10
10
|
end
|
11
11
|
end
|
data/lib/menilite/version.rb
CHANGED
data/menilite.gemspec
CHANGED
@@ -21,6 +21,9 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.12"
|
22
22
|
spec.add_development_dependency "rake", "~> 10.0"
|
23
23
|
spec.add_development_dependency "rspec", "~> 3.0"
|
24
|
+
spec.add_development_dependency 'opal-rspec', '0.5.0'
|
24
25
|
|
26
|
+
spec.add_runtime_dependency "opal"
|
27
|
+
spec.add_runtime_dependency 'opal-browser'
|
25
28
|
spec.add_runtime_dependency "sinatra-activerecord"
|
26
29
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: menilite
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- youchan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,6 +52,48 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: opal-rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.5.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.5.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: opal
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: opal-browser
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
55
97
|
- !ruby/object:Gem::Dependency
|
56
98
|
name: sinatra-activerecord
|
57
99
|
requirement: !ruby/object:Gem::Requirement
|