recline 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +124 -0
- data/lib/recline/appearance.rb +36 -0
- data/lib/recline/attribute_reflection.rb +13 -0
- data/lib/recline/model.rb +30 -0
- data/lib/recline/model_reflection.rb +13 -0
- data/lib/recline/railtie.rb +7 -0
- data/lib/recline/types/appearance_enum_type.rb +8 -0
- data/lib/recline/types/attribute_reflection_type.rb +13 -0
- data/lib/recline/types/model_reflection_type.rb +5 -0
- data/lib/recline/version.rb +3 -0
- data/lib/recline.rb +49 -0
- metadata +103 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c8a9590957c1a76c1a8fbd07e33e989e6d62657e
|
4
|
+
data.tar.gz: 71614ece35e0bd3213b25886fb3f2e8e20c01d67
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9dee9e3d0f625fd9eb532419b52618ff2793d3a2eef07e1b118042f65531054d62f01ac6fa5cdac5fdf8c168f0ef91fffbef680c8242021f1c13fe41c4ddceee
|
7
|
+
data.tar.gz: bfe5da5e83c87a81534158ddac727b4523ab85238509055e2236e3d69829fce00fc154d92e61ccc3362c25e69e60437c6ae58b9dc9b43f4c1acf478801f1e807
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2017 Cole Turner
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
# Recline for Rails
|
2
|
+
Seamless form management for React using GraphQL.
|
3
|
+
|
4
|
+
**Work in progress.**
|
5
|
+
|
6
|
+
## What is this?
|
7
|
+
This is a work in progress that is used for exposing data models through GraphQL for the purpose of building seamless forms.
|
8
|
+
|
9
|
+
The goal here is to provide an interface between the backend and frontend of web applications to control how form inputs should look and function with reusable components. Furthermore to allow
|
10
|
+
customization by creating extensions to existing field components and foster a collection of these extensions.
|
11
|
+
|
12
|
+
|
13
|
+
## How does it work?
|
14
|
+
Recline is a layer to provide data-backed instructions for how to display and validate forms for your ActiveRecord and ActiveModel object types. The heart of Recline is within
|
15
|
+
[GraphQL::Rails::ActiveReflection](/colepatrickturner/graphql-rails-activereflection) providing the core schema for reflecting upon models.
|
16
|
+
|
17
|
+
This layer augments the core schema to facilitate the display of forms through the set of React Javascript components that will be released under the same name. This is done through what is called
|
18
|
+
`Appearance` types. These component types are responsible for coercing inputs and outputs to the proper formats, and validating input through the reflections provided over GraphQL.
|
19
|
+
|
20
|
+
By default, database types are mapped to a set of Appearance types:
|
21
|
+
```ruby
|
22
|
+
Recline.default_appearance_types = {
|
23
|
+
string: :string,
|
24
|
+
text: :text,
|
25
|
+
integer: :number,
|
26
|
+
float: :number,
|
27
|
+
decimal: :number,
|
28
|
+
boolean: :toggle,
|
29
|
+
date: :date,
|
30
|
+
datetime: :datetime,
|
31
|
+
timestamp: :datetime
|
32
|
+
}
|
33
|
+
```
|
34
|
+
|
35
|
+
Help me explain this better:
|
36
|
+
[https://github.com/colepatrickturner/recline.rails/compare](Create a pull request)
|
37
|
+
|
38
|
+
# Installation
|
39
|
+
To begin, install the gem by adding it to the `Gemfile`:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
gem 'recline'
|
43
|
+
```
|
44
|
+
|
45
|
+
Add the following line to an object type that you would like to expose:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
implements GraphQL::Rails::ActiveReflection::Model.interface, inherit: true
|
49
|
+
```
|
50
|
+
|
51
|
+
And that's it! This will add a `_model` field to your object type that will expose any field that can be mapped to an ActiveModel/ActiveRecord attribute.
|
52
|
+
|
53
|
+
Example query fragment:
|
54
|
+
|
55
|
+
```graphql
|
56
|
+
fragment on YourObjectType {
|
57
|
+
_model: ReclineModel {
|
58
|
+
attributes: [ReclineAttribute] {
|
59
|
+
name: String
|
60
|
+
field_name: String
|
61
|
+
appearance: ReclineAppearance
|
62
|
+
|
63
|
+
validators: [ActiveReflectionValidator] {
|
64
|
+
absence: Boolean
|
65
|
+
presence: Boolean
|
66
|
+
uniqueness: Boolean
|
67
|
+
with_format: String
|
68
|
+
without_format: String
|
69
|
+
min_length: Integer
|
70
|
+
max_length: Integer
|
71
|
+
inclusion: [String]
|
72
|
+
exclusion: [String]
|
73
|
+
}
|
74
|
+
|
75
|
+
validate(int: Integer, str: String, float: Float, bool: Boolean): ActiveReflectionValidation {
|
76
|
+
valid: Boolean
|
77
|
+
errors: [String]
|
78
|
+
}
|
79
|
+
}
|
80
|
+
}
|
81
|
+
}
|
82
|
+
```
|
83
|
+
|
84
|
+
There are a few types to be aware of:
|
85
|
+
|
86
|
+
- ReclineModel
|
87
|
+
- ReclineAttribute
|
88
|
+
- ActiveReflectionValidator
|
89
|
+
- ActiveReflectionValidation
|
90
|
+
|
91
|
+
|
92
|
+
### Via GraphQL::Rails::ActiveReflection
|
93
|
+
|
94
|
+
The `_model` field will resolve to whatever type `Schema.resolve_type` returns for that object.
|
95
|
+
Only the fields on that type will be exposed as `attributes` - where `name` is the attribute name and `field_name` is the field name that exposed the attribute.
|
96
|
+
|
97
|
+
Each of the validators corresponds to the standard Rails validators. Almost all validators for an attribute will be returned, **except those that have the `if` or `unless` conditionals.** This is by design and therefore make note that any conditional validations will have to be performed manually.
|
98
|
+
|
99
|
+
There is also the `validate(...)` field with arguments for standard scalar types. Any one of the arguments can be provided, but only one. The result will contain a `valid` boolean and a list of `errors` strings returned from the validators.
|
100
|
+
|
101
|
+
In the future all of the `validate(...)` should be chained for a single call.
|
102
|
+
|
103
|
+
## Direction
|
104
|
+
Motivation for this repo is hand in hand with ActiveReflection - where anything that is model specific will be delegated there and anything that is UI specific will reside here.
|
105
|
+
|
106
|
+
# Needs Help
|
107
|
+
If you wish to contribute to this project, any pull request is warmly welcomed.
|
108
|
+
|
109
|
+
## Todo
|
110
|
+
### Rules for complex default types
|
111
|
+
- [ ] Dropdown when attribute has inclusion validator and more than three options
|
112
|
+
- [ ] Radio when attribute has inclusion validator and less than three options
|
113
|
+
### Appearance options
|
114
|
+
- [ ] Precision and scale for number types
|
115
|
+
- [ ] Date and time format types
|
116
|
+
- [ ] Toggle off/on label text
|
117
|
+
|
118
|
+
## Meta
|
119
|
+
- [ ] Documentation
|
120
|
+
- [ ] Examples
|
121
|
+
- [ ] Unit Tests
|
122
|
+
|
123
|
+
# Credits
|
124
|
+
- Cole Turner ([@colepatrickturner](https://github.com/colepatrickturner))
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Recline
|
2
|
+
class Appearance
|
3
|
+
@types = [
|
4
|
+
:none,
|
5
|
+
:string,
|
6
|
+
:text,
|
7
|
+
:markdown,
|
8
|
+
:url,
|
9
|
+
:email,
|
10
|
+
:number,
|
11
|
+
:select,
|
12
|
+
:date,
|
13
|
+
:time,
|
14
|
+
:datetime,
|
15
|
+
:color,
|
16
|
+
:toggle,
|
17
|
+
:range,
|
18
|
+
:tel,
|
19
|
+
:dropdown,
|
20
|
+
:rating,
|
21
|
+
:radio,
|
22
|
+
:checkbox,
|
23
|
+
:location,
|
24
|
+
:media,
|
25
|
+
:link
|
26
|
+
]
|
27
|
+
|
28
|
+
def self.define_type(input)
|
29
|
+
@types << input.to_sym
|
30
|
+
end
|
31
|
+
|
32
|
+
class << self
|
33
|
+
attr_reader :types
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Recline::AttributeReflection < GraphQL::Rails::ActiveReflection::AttributeReflection
|
2
|
+
@schema_name = "ReclineAttribute"
|
3
|
+
attr_accessor :appearance
|
4
|
+
|
5
|
+
def initialize(field, klass, schema)
|
6
|
+
super
|
7
|
+
@appearance = Recline.appearance_for(klass, @name)
|
8
|
+
end
|
9
|
+
|
10
|
+
def primary_key?
|
11
|
+
@klass.primary_key == @name
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Recline
|
2
|
+
class Model < GraphQL::Rails::ActiveReflection::Model
|
3
|
+
def self.interface
|
4
|
+
@interface ||= GraphQL::InterfaceType.define do
|
5
|
+
name "ReclineInterface"
|
6
|
+
field('_model', Recline::Types::ModelReflectionType, 'Model of attributes for field.') do
|
7
|
+
description('Fetch the content model for the given object.')
|
8
|
+
resolve(Recline::ModelReflection)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.field(**kwargs, &block)
|
14
|
+
# We have to define it fresh each time because
|
15
|
+
# its name will be modified and its description
|
16
|
+
# _may_ be modified.
|
17
|
+
field = GraphQL::Field.define do
|
18
|
+
type(Recline::Model.interface)
|
19
|
+
description('Fetch the content model for the given object.')
|
20
|
+
resolve(Recline::ModelReflection)
|
21
|
+
end
|
22
|
+
|
23
|
+
if kwargs.any? || block
|
24
|
+
field = field.redefine(kwargs, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
field
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Recline::ModelReflection < GraphQL::Rails::ActiveReflection::ModelReflection
|
2
|
+
@schema_name = "ReclineModel"
|
3
|
+
|
4
|
+
def get_attributes
|
5
|
+
@attributes ||= @type.fields.map { |name, field|
|
6
|
+
# No reflection if it's not a model attribute
|
7
|
+
property = field.property || name
|
8
|
+
if include_property? property
|
9
|
+
Recline::AttributeReflection.new(field, @klass, @schema)
|
10
|
+
end
|
11
|
+
}.compact
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'graphql/rails/active_reflection/types/attribute_reflection_type'
|
2
|
+
Recline::Types::AttributeReflectionType = GraphQL::Rails::ActiveReflection::Types::AttributeReflectionType.redefine do
|
3
|
+
name "ReclineAttribute"
|
4
|
+
field :appearance, Recline::Types::AppearanceEnumType
|
5
|
+
|
6
|
+
field :read_only, types.Boolean do
|
7
|
+
resolve ->(obj, _args, _ctx) do
|
8
|
+
!obj.primary_key?
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
puts "Recline::Types::AttributeReflectionType = #{Recline::Types::AttributeReflectionType}"
|
@@ -0,0 +1,5 @@
|
|
1
|
+
require 'graphql/rails/active_reflection/types/model_reflection_type'
|
2
|
+
Recline::Types::ModelReflectionType = GraphQL::Rails::ActiveReflection::Types::ModelReflectionType.redefine do
|
3
|
+
name 'ReclineModel'
|
4
|
+
field :attributes, Recline::Types::AttributeReflectionType.to_list_type
|
5
|
+
end
|
data/lib/recline.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'graphql'
|
2
|
+
|
3
|
+
module Recline
|
4
|
+
def self.appearance_for(klass, name)
|
5
|
+
if klass.respond_to? :recline_appearance
|
6
|
+
klass.recline_appearance(@name)
|
7
|
+
else
|
8
|
+
db_type = klass.type_for_attribute(name.to_s).type
|
9
|
+
if default_appearance_types.key? db_type
|
10
|
+
default_appearance_types[db_type]
|
11
|
+
else
|
12
|
+
fallback_appearance
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class << self
|
18
|
+
@schema_name_prefix = 'Recline'
|
19
|
+
@fallback_appearance = :string
|
20
|
+
|
21
|
+
attr_accessor :schema_name_prefix
|
22
|
+
attr_accessor :fallback_appearance
|
23
|
+
attr_accessor :default_appearance_types
|
24
|
+
|
25
|
+
def default_appearance_types
|
26
|
+
@default_appearance_types ||= {
|
27
|
+
string: :string,
|
28
|
+
text: :text,
|
29
|
+
integer: :number,
|
30
|
+
float: :number,
|
31
|
+
decimal: :number,
|
32
|
+
boolean: :toggle,
|
33
|
+
date: :date,
|
34
|
+
datetime: :datetime,
|
35
|
+
timestamp: :datetime
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
require 'recline/railtie' if defined?(Rails)
|
42
|
+
require 'recline/model'
|
43
|
+
require 'recline/attribute_reflection'
|
44
|
+
require 'recline/model_reflection'
|
45
|
+
require 'recline/appearance'
|
46
|
+
require 'recline/types/appearance_enum_type'
|
47
|
+
require 'recline/types/attribute_reflection_type'
|
48
|
+
require 'recline/types/model_reflection_type'
|
49
|
+
require 'recline/appearance'
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: recline
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Cole Turner
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-04-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: graphql
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.5.0
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '2.0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.5.0
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.0'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: activerecord
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 4.2.1
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 4.2.1
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: activemodel
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 4.2.1
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 4.2.1
|
61
|
+
description: Keep your frontend forms sane and seamless with your backend
|
62
|
+
email: turner.cole@gmail.com
|
63
|
+
executables: []
|
64
|
+
extensions: []
|
65
|
+
extra_rdoc_files: []
|
66
|
+
files:
|
67
|
+
- LICENSE
|
68
|
+
- README.md
|
69
|
+
- lib/recline.rb
|
70
|
+
- lib/recline/appearance.rb
|
71
|
+
- lib/recline/attribute_reflection.rb
|
72
|
+
- lib/recline/model.rb
|
73
|
+
- lib/recline/model_reflection.rb
|
74
|
+
- lib/recline/railtie.rb
|
75
|
+
- lib/recline/types/appearance_enum_type.rb
|
76
|
+
- lib/recline/types/attribute_reflection_type.rb
|
77
|
+
- lib/recline/types/model_reflection_type.rb
|
78
|
+
- lib/recline/version.rb
|
79
|
+
homepage: http://rubygems.org/gems/recline
|
80
|
+
licenses:
|
81
|
+
- MIT
|
82
|
+
metadata: {}
|
83
|
+
post_install_message:
|
84
|
+
rdoc_options: []
|
85
|
+
require_paths:
|
86
|
+
- lib
|
87
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: 2.3.0
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
requirements: []
|
98
|
+
rubyforge_project:
|
99
|
+
rubygems_version: 2.6.8
|
100
|
+
signing_key:
|
101
|
+
specification_version: 4
|
102
|
+
summary: Seamless form management for React using GraphQL.
|
103
|
+
test_files: []
|