menilite 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.
- 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
|