wabur 0.1.0d1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f881d414a328e743c262513bde6977d3a28a3ec3
4
+ data.tar.gz: f3d99084f2ad9ccb619ceb3572a4c0bc66863c5f
5
+ SHA512:
6
+ metadata.gz: 0b4ca9f500c474908d6a4b740a86ec360f0386332e7d55bd724743124d041983c1854834cbac66a874c73b2a7f1b3c674224c830a4d0b3dee3f50204efe89b3f
7
+ data.tar.gz: b71155371f81f098034483486ff036e36ccaee5c460072dc61a7fe3012df97de643c2eea5514c9561f50ace56c5b1685cbde4cd04e3a322d5dd490ce15f71f1a
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Peter Ohler
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,58 @@
1
+ # WABuR (Web Application Builder using Ruby)
2
+
3
+ Ruby is a great language but for performance C is a better alternative. It is
4
+ possible to get the best of both as evident with [Oj](http://www.ohler.com/oj)
5
+ and [Ox](http://www.ohler.com/ox). C by itself allowed
6
+ [Piper](http://piperpushcache.com), a fast push web server to be developed and
7
+ is being used to develop [OpO](http://opo.technology) a high performance graph
8
+ and JSON database. This project takes from all of those projects for a hight
9
+ performance Ruby web framework.
10
+
11
+ Ruby on Rails has made Ruby main stream. While RoR is fine for some
12
+ applications there are others that might be better served with an alternative.
13
+ This project was started as an alternative to Ruby on Rails with a focus on
14
+ performance and easy of use.
15
+
16
+ Why develop an alternative to Rails? Rails popularity has been waning. It is
17
+ still huge but not as popular as it used to be. RoR is not going away any time
18
+ soon but for some applications alternatives are needed.
19
+
20
+ ## Goals
21
+
22
+ Lets start with the assumption that we want to continue to use Ruby. The goal
23
+ of this project is to provide a high performance, easy to use, and fully
24
+ featured web framework with Ruby at the core. By keeping the core, the
25
+ business logic in Ruby but allowing options for other parts to be in different
26
+ languages the best use of each can be utilized.
27
+
28
+ Targets are a throughput of 100K page fetches per second at a latency of no
29
+ more than 1 millisecond on a desktop machine. That is more than an order of
30
+ magnitude faster than Rails and on par with other top of the performance tier
31
+ web frameworks across all languages.
32
+
33
+ [Continue reading ...](pages/Goals.md)
34
+
35
+ ## Architecture
36
+
37
+ The architecture provides many options but it keeps clean and clear APIs
38
+ between modules. This pluggable design allows for unit test drivers and
39
+ various levels of deployment options from straight Ruby to a high performance
40
+ C shell that handles HTTP and data storage.
41
+
42
+ ![](http://www.opo.technology/wab/wab_arch.svg)
43
+
44
+ [Continue reading ...](pages/Architecture.md)
45
+
46
+ ## Participate
47
+
48
+ If you like the idea and want to help out or become a core developer on the
49
+ project send me an [email](mailto:peter@ohler.com). Get in on the ground floor
50
+ and lets make something awesome together.
51
+
52
+ ## Planning
53
+
54
+ The plan is informal and high level until more details are defined.
55
+
56
+ [Details ...](pages/Plan.md)
57
+
58
+
@@ -0,0 +1,175 @@
1
+ module WAB
2
+
3
+ # A Controller class or a duck-typed alternative should be created and
4
+ # registered with a Shell for any type that implements behavior other than
5
+ # the default REST API processing. If a public method is not found on the
6
+ # class instance then the default REST API processing will be used.
7
+ #
8
+ # A description of the available methods is included as private methods.
9
+ class Controller # :doc: all
10
+ attribute_accessor :shell
11
+ attribute_accessor :view
12
+ attribute_accessor :model
13
+
14
+ # Create a instance.
15
+ def initialize()
16
+ @shell = nil
17
+ @view = shell.view
18
+ @model = shell.model
19
+ # TBD
20
+ end
21
+
22
+ # Handler for paths that do not match the REST pattern. Only called on the
23
+ # default controller.
24
+ #
25
+ # Processing result are passed back to the view which forward the result
26
+ # on to the requester. The result, is not nil, should be a Data instance.
27
+ #
28
+ # path:: identifies operation and additional data in a / delimited
29
+ # format. It is up to the controller to decide how to process the
30
+ # request.
31
+ # data:: data to be processed
32
+ def handle(path, data)
33
+ nil
34
+ end
35
+
36
+ # To make the desired methods active while processing the desired method
37
+ # should be made public in the subclasses. If the methods remain private
38
+ # they will not be called.
39
+ private
40
+
41
+ # Should create a new data object.
42
+ #
43
+ # The return should be the identifier for the object created or if
44
+ # +with_data+ is true a Data object with an +id+ attribute and a +data+
45
+ # attribute that contains the full object details.
46
+ #
47
+ # On error an Exception should be raised.
48
+ #
49
+ # data:: the data to use as a new object.
50
+ # with_data:: flag indicating the response should include the new object
51
+ def create(data, with_data=false) # :doc:
52
+ # TBD implement the default behavior as an example or starting point
53
+ end
54
+
55
+ # Should return the object with the +id+ provided.
56
+ #
57
+ # The function should return the result of a fetch on the model with the
58
+ # provided +id+. The result should be a Data instance which is either the
59
+ # object data or a wrapper that include the object id in an +id+ attribute
60
+ # and the object data itself in a +data+ attribute depending on the value
61
+ # of the +with_id+ argument.
62
+ #
63
+ # id:: identifier of the object
64
+ # with_id:: if true wrap the object data with an envelope that includes
65
+ # the id as well as the object data.
66
+ def read(id, with_id=false) # :doc:
67
+ # TBD implement the default behavior as an example or starting point
68
+ end
69
+
70
+ # Should return the objects with attributes matching the +attrs+ argument.
71
+ #
72
+ # The return should be a Hash where the keys are the matching object
73
+ # identifiers and the value are the object data. An empty Hash or nil
74
+ # indicates there were no matches.
75
+ #
76
+ # attrs:: a Hash with keys matching paths into the target objects and value
77
+ # equal to the target attribute values. A path can be an array of
78
+ # keys used to walk a path to the target or a +.+ delimited set of
79
+ # keys.
80
+ def read_by_attrs(attrs) # :doc:
81
+ # TBD implement the default behavior as an example or starting point
82
+ end
83
+
84
+ # Replaces the object data for the identified object.
85
+ #
86
+ # The return should be the identifier for the object updated or if
87
+ # +with_data+ is true a Data object with an +id+ attribute and a +data+
88
+ # attribute that contains the full object details. Note that depending on
89
+ # the implemenation the identifier may change as a result of an update.
90
+ #
91
+ # On error an Exception should be raised.
92
+ #
93
+ # id:: identifier of the object to be replaced
94
+ # data:: the data to use as a new object.
95
+ # with_data:: flag indicating the response should include the new object
96
+ def update(id, data, with_data=false) # :doc:
97
+ # TBD implement the default behavior as an example or starting point
98
+ end
99
+
100
+ # Delete the identified object.
101
+ #
102
+ # On success the deleted object identifier is returned. If the object is
103
+ # not found then nil is returned. On error an Exception should be raised.
104
+ #
105
+ # id:: identifier of the object to be deleted
106
+ def delete(id) # :doc:
107
+ # TBD implement the default behavior as an example or starting point
108
+ end
109
+
110
+ # Delete all object that match the set of provided attribute values.
111
+ #
112
+ # An array of deleted object identifiers should be returned.
113
+ #
114
+ # attrs:: a Hash with keys matching paths into the target objects and value
115
+ # equal to the target attribute values. A path can be an array of
116
+ # keys used to walk a path to the target or a +.+ delimited set of
117
+ # keys.
118
+ def delete_by_attrs(attrs) # :doc:
119
+ # TBD implement the default behavior as an example or starting point
120
+ end
121
+
122
+ # Return a Hash of all the objects of the type associated with the
123
+ # controller.
124
+ #
125
+ # The return hash keys should be the identifiers of the objects and the
126
+ # the values should be either nil or the object data if the +with_data+
127
+ # flag is true. If the response will be larger than supported one of the
128
+ # keys should be the empty string which indicated additional instance
129
+ # exists and were not provided.
130
+ #
131
+ # Note that this could return a very large set of data. If the number of
132
+ # instances in the type is large the +search()+ might be more appropriate
133
+ # as it allows for paging of results and sorting.
134
+ #
135
+ # with_data:: flag indicating the return should include object data
136
+ def list(with_data=false) # :doc:
137
+ # TBD implement the default behavior as an example or starting point
138
+ end
139
+
140
+ # Search using a TQL SELECT.
141
+ #
142
+ # The provided TQL[http://opo.technology/pages/doc/tql/index.html] can be
143
+ # either the JSON syntax or the friendly syntax. The call exists on the
144
+ # controller to allow filtering and permission checking before
145
+ # execution. Only the default controller is expected to provide a public
146
+ # version of this method.
147
+ #
148
+ # query:: query
149
+ # format:: can be one of :TQL or :TQL_JSON. The :GraphQL option is
150
+ # reserved for the future.
151
+ def search(query, format=:TQL) # :doc:
152
+ # TBD implement the default behavior as an example or starting point
153
+ end
154
+
155
+ # Subscribe to changes in data pushed from the model that will be passed
156
+ # to the view with the +push+ method if it passes the supplied filter.
157
+ #
158
+ # The +view+ +changed+ method is called when changes in data cause
159
+ # the associated object to pass the provided filter.
160
+ #
161
+ # filter:: the filter to apply to the data. TBD the nature of the filter is pending.
162
+ def subscribe(filter)
163
+ # TBD
164
+ end
165
+
166
+ # Called by the model when data changes if supported by the model storage
167
+ # component.
168
+ #
169
+ # data:: the data that has changed
170
+ def changed(data) # :doc:
171
+ # TBD implement the default behavior as an example or starting point
172
+ end
173
+
174
+ end # Controller
175
+ end # WAB
data/lib/wab/data.rb ADDED
@@ -0,0 +1,73 @@
1
+
2
+ module WAB
3
+
4
+ # The class representing the cananical data structure in WAB. Typically the
5
+ # Data instances are factory created by the Shell and will most likely not
6
+ # be instance of this class but rather a class that is a duck-type of this
7
+ # class (has the same methods and behavior).
8
+ class Data
9
+
10
+ # This method is included only for testing purposes of the Ruby base
11
+ # Shell. It should only be called by the Shell. Create a new Data instance
12
+ # with the initial value provided. The value must be a Hash or Array. The
13
+ # members of the Hash or Array must be nil, boolean, String, Integer,
14
+ # Float, BigDecimal, Array, Hash, Time, WAB::UUID, or WAB::IRI.
15
+ def initialize(value=nil)
16
+ # TBD
17
+ end
18
+
19
+ # Gets the Data element or value identified by the path where the path
20
+ # elements are separated by the '.' character. The path can also be a
21
+ # array of path node identifiers. For example, child.grandchild is the
22
+ # same as ['child', 'grandchild'].
23
+ def get(path)
24
+ # TBD
25
+ end
26
+
27
+ # Sets the node value identified by the path where the path elements are
28
+ # separated by the '.' character. The path can also be a array of path
29
+ # node identifiers. For example, child.grandchild is the same as ['child',
30
+ # 'grandchild']. The value must be one of the allowed data values
31
+ # described in the initialize method.
32
+ def set(path, value)
33
+ # TBD
34
+ end
35
+
36
+ # Each child of the Data instance is provided as an argument to a block
37
+ # when the each method is called.
38
+ def each()
39
+ # TBD
40
+ end
41
+
42
+ # Each leaf of the Data instance is provided as an argument to a block
43
+ # when the each method is called. A leaf is a primitive that has no
44
+ # children and will be nil, a Boolean, String, Numberic, Time, WAB::UUID,
45
+ # or WAB::IRI.
46
+ def each_leaf()
47
+ # TBD
48
+ end
49
+
50
+ # Make a deep copy of the Data instance.
51
+ def clone()
52
+ # TBD
53
+ end
54
+
55
+ # Returns the instance converted to native Ruby values such as a Hash,
56
+ # Array, etc.
57
+ def native()
58
+ # TBD
59
+ end
60
+
61
+ # Returns true if self and other are either the same or have the same
62
+ # contents. This is a deep comparison.
63
+ def eql?(other)
64
+ # TBD
65
+ end
66
+
67
+ # Encode the data as a JSON string.
68
+ def json(indent=0)
69
+ # TBD
70
+ end
71
+
72
+ end # Data
73
+ end # WAB
data/lib/wab/model.rb ADDED
@@ -0,0 +1,136 @@
1
+
2
+ module WAB
3
+
4
+ # Represents the model portion of a MVC design pattern. It must respond to
5
+ # request to update the store using either the CRUD type operations that
6
+ # match the controller.
7
+ class Model
8
+
9
+ # Should create a new data object.
10
+ #
11
+ # The return should be the identifier for the object created or if
12
+ # +with_data+ is true a Data object with an +id+ attribute and a +data+
13
+ # attribute that contains the full object details.
14
+ #
15
+ # On error an Exception should be raised.
16
+ #
17
+ # data:: the data to use as a new object.
18
+ # with_data:: flag indicating the response should include the new object
19
+ def create(data, with_data=false) # :doc:
20
+ # TBD implement the default behavior as an example or starting point
21
+ end
22
+
23
+ # Should return the object with the +id+ provided.
24
+ #
25
+ # The function should return the result of a fetch on the model with the
26
+ # provided +id+. The result should be a Data instance which is either the
27
+ # object data or a wrapper that include the object id in an +id+ attribute
28
+ # and the object data itself in a +data+ attribute depending on the value
29
+ # of the +with_id+ argument.
30
+ #
31
+ # id:: identifier of the object
32
+ # with_id:: if true wrap the object data with an envelope that includes
33
+ # the id as well as the object data.
34
+ def read(id, with_id=false) # :doc:
35
+ # TBD implement the default behavior as an example or starting point
36
+ end
37
+
38
+ # Should return the objects with attributes matching the +attrs+ argument.
39
+ #
40
+ # The return should be a Hash where the keys are the matching object
41
+ # identifiers and the value are the object data. An empty Hash or nil
42
+ # indicates there were no matches.
43
+ #
44
+ # attrs:: a Hash with keys matching paths into the target objects and value
45
+ # equal to the target attribute values. A path can be an array of
46
+ # keys used to walk a path to the target or a +.+ delimited set of
47
+ # keys.
48
+ def read_by_attrs(attrs) # :doc:
49
+ # TBD implement the default behavior as an example or starting point
50
+ end
51
+
52
+ # Replaces the object data for the identified object.
53
+ #
54
+ # The return should be the identifier for the object updated or if
55
+ # +with_data+ is true a Data object with an +id+ attribute and a +data+
56
+ # attribute that contains the full object details. Note that depending on
57
+ # the implemenation the identifier may change as a result of an update.
58
+ #
59
+ # On error an Exception should be raised.
60
+ #
61
+ # id:: identifier of the object to be replaced
62
+ # data:: the data to use as a new object.
63
+ # with_data:: flag indicating the response should include the new object
64
+ def update(id, data, with_data=false) # :doc:
65
+ # TBD implement the default behavior as an example or starting point
66
+ end
67
+
68
+ # Delete the identified object.
69
+ #
70
+ # On success the deleted object identifier is returned. If the object is
71
+ # not found then nil is returned. On error an Exception should be raised.
72
+ #
73
+ # id:: identifier of the object to be deleted
74
+ def delete(id) # :doc:
75
+ # TBD implement the default behavior as an example or starting point
76
+ end
77
+
78
+ # Delete all object that match the set of provided attribute values.
79
+ #
80
+ # An array of deleted object identifiers should be returned.
81
+ #
82
+ # attrs:: a Hash with keys matching paths into the target objects and value
83
+ # equal to the target attribute values. A path can be an array of
84
+ # keys used to walk a path to the target or a +.+ delimited set of
85
+ # keys.
86
+ def delete_by_attrs(attrs) # :doc:
87
+ # TBD implement the default behavior as an example or starting point
88
+ end
89
+
90
+ # Return a Hash of all the objects of the type associated with the
91
+ # controller.
92
+ #
93
+ # The return hash keys should be the identifiers of the objects and the
94
+ # the values should be either nil or the object data if the +with_data+
95
+ # flag is true. If the response will be larger than supported one of the
96
+ # keys should be the empty string which indicated additional instance
97
+ # exists and were not provided.
98
+ #
99
+ # Note that this could return a very large set of data. If the number of
100
+ # instances in the type is large the +search()+ might be more appropriate
101
+ # as it allows for paging of results and sorting.
102
+ #
103
+ # with_data:: flag indicating the return should include object data
104
+ def list(with_data=false) # :doc:
105
+ # TBD implement the default behavior as an example or starting point
106
+ end
107
+
108
+ # Search using a TQL SELECT.
109
+ #
110
+ # The provided TQL[http://opo.technology/pages/doc/tql/index.html] can be
111
+ # either the JSON syntax or the friendly syntax. The call exists on the
112
+ # controller to allow filtering and permission checking before
113
+ # execution. Only the default controller is expected to provide a public
114
+ # version of this method.
115
+ #
116
+ # query:: query
117
+ # format:: can be one of :TQL or :TQL_JSON. The :GraphQL option is
118
+ # reserved for the future.
119
+ def search(query, format=:TQL) # :doc:
120
+ # TBD implement the default behavior as an example or starting point
121
+ end
122
+
123
+ # Subscribe to changes in stored data and push changes to the controller
124
+ # if it passes the supplied filter.
125
+ #
126
+ # The +controller+ +changed+ method is called when changes in data cause
127
+ # the associated object to pass the provided filter.
128
+ #
129
+ # controller:: the controller to notify of changed
130
+ # filter:: the filter to apply to the data. Syntax is that TQL uses for the FILTER clause.
131
+ def subscribe(controller, filter)
132
+ # TBD
133
+ end
134
+
135
+ end # Model
136
+ end # WAB
data/lib/wab/shell.rb ADDED
@@ -0,0 +1,46 @@
1
+ module WAB
2
+
3
+ # The Shell is a duck-typed class. Any shell alternative should implement
4
+ # all the methods defined in the class except the +initialize+ method. This
5
+ # class is also the default Ruby version of the shell that can be used for
6
+ # development and small systems.
7
+ class Shell
8
+
9
+ # Sets up the shell with a view, model, and type_key.
10
+ def initialize(view, model, type_key='kind')
11
+ @view = view
12
+ @model = model
13
+ @controllers = {}
14
+ @type_key = type_key
15
+ end
16
+
17
+ # Returns the view instance that can be used for pushing data to a view.
18
+ def view()
19
+ @view
20
+ end
21
+
22
+ # Returns the model instance that can be used to get and modify data in
23
+ # the data store.
24
+ def model()
25
+ @model
26
+ end
27
+
28
+ # Returns the path where a data type is located. The default is 'kind'.
29
+ def type_key()
30
+ @type_key
31
+ end
32
+
33
+ # Register a controller for a named type.
34
+ #
35
+ # If a request is received for an unregistered type the default controller
36
+ # will be used. The default controller is registered with a +nil+ key.
37
+ #
38
+ # type:: type name
39
+ # controller:: Controller instance for handling requests for the identified +type+
40
+ def register_controller(type, controller)
41
+ controller.shell = self
42
+ @controllers[type] = controller
43
+ end
44
+
45
+ end # Shell
46
+ end # WAB
@@ -0,0 +1,5 @@
1
+
2
+ module WAB
3
+ # Current version of the module.
4
+ VERSION = '0.1.0d1'
5
+ end
data/lib/wab/view.rb ADDED
@@ -0,0 +1,21 @@
1
+ module WAB
2
+
3
+ # Represents the view in the MVC design pattern. It is primarily used to
4
+ # call the controller with requests but can be used to push data out to a
5
+ # display if push is supported.
6
+ #
7
+ # This class is the default implementation.
8
+ class View
9
+
10
+ def initialize()
11
+ # TBD as the default implementation this should be an HTTP server that
12
+ # serves files as well as JSON to a Javascript enabled browser.
13
+ end
14
+
15
+ # Push changed data to a display.
16
+ def changed(data)
17
+ # TBD
18
+ end
19
+
20
+ end # View
21
+ end # WAB
data/lib/wab.rb ADDED
@@ -0,0 +1,5 @@
1
+
2
+ # Web Application Builder
3
+ module WAB
4
+ end
5
+
@@ -0,0 +1,200 @@
1
+ # Architecture
2
+
3
+ The WAB architecture is a Mode View Controller with clear APIs between each
4
+ part of the MVC. The design allows the non-business related tasks such as the
5
+ HTTP server and data store to be treated as service to the Controller which
6
+ contains the business logic.
7
+
8
+ ![](http://www.opo.technology/wab/wab_arch.svg)
9
+
10
+ ## MVC
11
+
12
+ The Model View Controller pattern is a well known and widely accepted design
13
+ pattern. It is also the pattern used by Rails. WAB adheres to this model with
14
+ well defined APIs that are used exclusively.
15
+
16
+ The MVC pattern has many variants with some functionality being in different
17
+ components depending on how the lines are drawn between those components. No
18
+ matter what the separation, if it is clear many issues can be avoided.
19
+
20
+ ### Model
21
+
22
+ The Model component is responsible for persisting data, providing search and
23
+ retrieval capabilities, and assuring stored consistency. The Model does not
24
+ assure business logic consistency nor does it enforce relationships between
25
+ data elements. It is a data store only.
26
+
27
+ The data in the system is follows a JSON structural model. This make a NoSQL
28
+ database an ideal store. It does mean that the Model data is unstructured in
29
+ that there is no schema enforced by the data store. It does not mean that
30
+ relationships do not exist in the data store.
31
+
32
+ With well defined APIs between the Model and the Controller almost any data
33
+ store can be used as long as an adapter is written. This allows options such
34
+ as [MongoDB](https://www.mongodb.com), [Redis](https://redislabs.com),
35
+ [OpO](http://opo.technology), a file based store, or even an in memory store
36
+ for testing.
37
+
38
+ One feature that may not be supported by all stores is the ability to push
39
+ changes from the data store to the Controller and then up to the View to real
40
+ time feeds.
41
+
42
+ ### View
43
+
44
+ An HTTP server provides the View environment. In addition to serving HTML,
45
+ CSS, images, and other files typically served by a web server the View server
46
+ also supports exchanging JSON data through a REST API. A WebSocket and SSE
47
+ capability is also expected and designed for in the API.
48
+
49
+ Javascript is the suggested language to use for web pages but any approach to
50
+ accepting and delivering JSON is fine. JaveScript helpers are provided that
51
+ support the REST API as well as the WebSocket and SSE push APIs.
52
+
53
+ ### Controller
54
+
55
+ With two approaches to connecting the Controller to the View and Model there
56
+ are deployment options that allow trading off latency for throughput. The
57
+ Controller code is isolated from those deployment choices except for the
58
+ choice of language. If the Controller is written in Ruby then it can be either
59
+ embedded in the shell or access as an external application.
60
+
61
+ The Controller is a bridge between the View and Model and implements the
62
+ business logic as needed. In the case of a fetch, create, or update options
63
+ are available to bypass or use the default Controller. The bypass allows a
64
+ more direct conduit between the View and the Model with the Controller just
65
+ passing the data along to the model and vice versa.
66
+
67
+ The Controller can also receive callbacks on changes in the Model which can
68
+ then be forwarded to the View if a subscription to that data has been made.
69
+
70
+ ## APIs
71
+
72
+ All APIs are described with Ruby code as the Controller is expected to be
73
+ Ruby. If an external Controller is to be used then the external glue API is
74
+ used. This API is a text based API over a pipe (Unix socket). Events can
75
+ arrive at the Controller from either the View or Model interface.
76
+
77
+ ### Data Model
78
+
79
+ Data is loosely represented as JSON. There are some expectations that can be
80
+ relaxed if desired.
81
+
82
+ #### JSON
83
+
84
+ The data exchanged between components follows the JSON model for primitives
85
+ with a few optional additions. The JSON types can be used exclusively and are:
86
+
87
+ - `null` (nil)
88
+ - _boolean_ (`true` | `false`)
89
+ - _string_ (String)
90
+ - _number_ (Integer | Float | BigDecimal)
91
+ - _object_ (Hash)
92
+ - _array_ (Array)
93
+
94
+ All string must be UTF-8 or Unicode.
95
+
96
+ Some other types are also allowed. Each has a defined JSON representation that
97
+ can be used instead.
98
+
99
+ - _time_ (Ruby Time encoded in RFC 3339 format if a string)
100
+ - _UUID_ (WAB::UUID encoded as defined by RFC 4122)
101
+ - _IRI_ (WAB::IRI encoded as defined by RFC 3987)
102
+
103
+ These types are represented by the WAB::Data class.
104
+
105
+ #### Structure
106
+
107
+ While object can be any JSON or WAB::Data they are encouraged to be JSON
108
+ Objects (Hash) types. I addition one attribute should be used to identify the
109
+ type. The default is the 'kind' attribute. That attribute is not required to
110
+ be the 'kind' attribute but can be anywhere in the data tree as long as it is
111
+ consistent across all types. As an example it could be in 'meta.kind' where
112
+ that key represents a path with a 'kind' element in a 'meta' object (Hash).
113
+
114
+ Each object or for that matter every node in a Data tree is assigned a system
115
+ wide unique identifier. That is used to identfiy each object when using the
116
+ API. From the view perspective a REST over HTTP is used.
117
+
118
+ #### Just Data
119
+
120
+ - just data and data helpers (get, set, inspect, to_s)
121
+ - nothing like to_json
122
+ - reasoning it that different uses require different behavior
123
+ - different stores, view, processing, etc
124
+ - use of delgate is encouraged
125
+
126
+
127
+ ### View/Controller
128
+
129
+ The View/Controller API is predominanty from View to Controller but the
130
+ ability for the Controller to push data to the View is also part of the
131
+ design. That allows pages to take advantage of WebSockets or SSEs to display
132
+ data changes as they occur.
133
+
134
+ See the Controller class documentation for further details.
135
+
136
+ ### Controller/Model
137
+
138
+ The Contoller/Model API is driven mostly from Controller to Model with the
139
+ Model responding to queries. Like the View/Controller API the Model can also
140
+ push changes to the Controller.
141
+
142
+ The Model supports basic CRUD operations as well as a query API that uses
143
+ [TQL](http://opo.technology/pages/doc/tql/index.html) in both the friendly and
144
+ JSON formats. Support for GraphQL is anticipated but not for the first
145
+ iteration.
146
+
147
+ See the Model class documentation for further details.
148
+
149
+ ## Shells
150
+
151
+ As noted in the architecture diagram, the WAB Shell can be either the C or
152
+ Ruby shell. The Ruby shell is intended for development and possibly small
153
+ installations. The C WAB Shell or Shells if more thna one is implemented are
154
+ intended to be high performance environments that the Controller code resides
155
+ in either as embedded code or through a piped connections.
156
+
157
+ ### Embedded
158
+
159
+ A C WAB Shell with an embedded Controller utilizes the View and Model APIs
160
+ directly through the Ruby library. This approach gives more control to the
161
+ Shell in regard to utilizing threads and C libraries outside of Ruby. An
162
+ alternative approach is to call C extensions from Ruby but that approach is
163
+ left for future if it makes sense.
164
+
165
+ The Ruby WAB Shell implements an HTTP server as well as either an in memory
166
+ data store or a file based data store.
167
+
168
+ The APIs are designed to allow relatively direct modifications to the data
169
+ store if the store supports such.
170
+
171
+ The embedded Shell should have the lowest latency but may sacrifice throughput
172
+ depending on the complexity of the Controller code.
173
+
174
+ ### External
175
+
176
+ Running external Controllers is implemented by the WAB Shell either spawning
177
+ the Controller application or connecting to an existing one. Multiple
178
+ Controllers can be active to allow parallel Controller processing. The
179
+ approach taken is the same as that used [Piper Push
180
+ Cache](http://piperpushcache.com) with the process flow [Spawn
181
+ Actor](http://piperpushcache.com/help_actor_spawn).
182
+
183
+ To run a Controller written in Ruby the External Glue is used to bridge the
184
+ gap between the WAB external API and the Controller APIs. This is a light
185
+ weught layer that converts to and from the text based pipe API and the Ruby
186
+ APIs.
187
+
188
+ With the ability to make use of multiple Controller instances which may reside
189
+ on different machines the throughput is expected to be higher than the
190
+ embedded Shell but with a degradation of the latency.
191
+
192
+ ### Alternatives
193
+
194
+ A straight Ruby WAB Shell is the choice for testing and for small
195
+ installations. The Ruby shell is the first choice when getting started.
196
+
197
+ Outside of this project WAB C or other language shells can be written. The
198
+ first is expected to be a derivative of [OpO](http://opo.technology) as it
199
+ takes shape. This WAB Shell will also draw on the libraries use by [Piper
200
+ Push Cache](http://piperpushcache.com) to provide WebSocket and SSE support.
data/pages/Goals.md ADDED
@@ -0,0 +1,110 @@
1
+ # Goals
2
+
3
+ The goal is to provide a high performance, easy to use, and fully featured web
4
+ framework that uses Ruby for business logic. Following a Model/View/Controller
5
+ model Ruby is used to implement the Controller portion. Using the best
6
+ language for each portion of the MVC the View is implemented in JavaScript,
7
+ HTML, and CSS. The Model is simply a NoSQL data store.
8
+
9
+ To address the ease of use clean and clear APIs are used between each part of
10
+ the MVC and JSON is the data representation throughout. Ruby is straight Ruby
11
+ with no monkey patched core classes and no magic. Plain and simple Ruby.
12
+
13
+ ## Performance
14
+
15
+ With a goal of building a high performance system the architecture is design
16
+ from the start to deliver the best performance possible. Code will also
17
+ developed with that goal in mind. All code will be unit tested and benchmarks
18
+ made where applicable.
19
+
20
+ ### Approach
21
+
22
+ The architecture is module and follows a Model View Controller design pattern
23
+ with clear and defined APIs between each module. This will ensure a clear
24
+ division between the Model, View, and Controller modules.
25
+
26
+ With a modular design the most appropriate data store can be selected. By
27
+ being able to swap out different storage modules choices can be made between
28
+ hooking up to an existing SQL or NoSQL data store or using a faster or more
29
+ scaleable choice.
30
+
31
+ A separation of data and behavior is part of the overall approach. By keeping
32
+ the data separate and devoid of behavior the movement of data between the
33
+ elements of the MVC doesn't drag along methods not appropriate for the
34
+ component. It also allows behavior to be implemented without impacting the
35
+ data and updated and modified without a global replacement of the system as a
36
+ whole. Related to this approach is that there will be absolutely no monkey
37
+ patching of core Ruby classes. Monkey patching creates unexpected behavior and
38
+ cause conflicts between modules.
39
+
40
+ Serialization must be fast and reduced to a minimum. The APIs provide an
41
+ abstraction that allows optimized data structures to be used as long as they
42
+ follow a JSON model view through the access APIs.
43
+
44
+ Ruby code is kept as simple and direct as possible to reduce the overhead of
45
+ deeply nested calls and object creation.
46
+
47
+ There are parts of the system that can be written in higher performance
48
+ languages such as C. This includes the HTTP and data stores. By allowing use
49
+ of a mixed environment the best performance can be achieved.
50
+
51
+ ### Targets
52
+
53
+ Targets are a throughput of 100K page fetches per second at a latency of no
54
+ more than 1 millisecond on a desktop machine. That is more than an order of
55
+ magnitude faster than Rails and on par with other top of the performance tier
56
+ web frameworks in all languages.
57
+
58
+ The throughput and latency targets are not unreasonable as
59
+ [OpO](http://opo.technology) as an HTTP server providing JSON documents with
60
+ the Ruby controller has demonstrated that 140K fetches per second with a
61
+ latency of 0.6 milliseconds is possible on a desktop machine. With a thin Ruby
62
+ controller or a bypass for simple fetches the additional overhead is minimal.
63
+
64
+ The system must be scaleable in at least one configuration. Possibly using
65
+ multiple Ruby instances as processes or threads.
66
+
67
+ In the final deployment the aim is for upper part of performance tier when
68
+ compared to other web framework across all languages. Right now in
69
+ [benchmarks](https://gist.github.com/omnibs/e5e72b31e6bd25caf39a) Rails and
70
+ Sinatra occupy the bottom slots. WAB will put Ruby near the top.
71
+
72
+ ## Easy to Use
73
+
74
+ In addition to performance goals WAB must be easy to use not only for a
75
+ 'Hello World' application but for advanced systems as well. The learning curve
76
+ must be shallow to allow new users to get started immediately and then
77
+ progress onto more advanced features.
78
+
79
+ ### Simplicity, Clear, and Simple
80
+
81
+ The Ruby code used in WAB will be simple and direct. There will be no
82
+ magic. Clear documented class definitions with shallow class hierachy
83
+ throughout.
84
+
85
+ ### Development
86
+
87
+ Development is a cycle of edit and test repeated over and over again. The
88
+ faster that cycle is the more friendly the development environment. Keep
89
+ modules encapsulated with well defined APIs allows this cycle to be fast as
90
+ unit tests just test against the APIs.
91
+
92
+ This strategy of well defined APIs and testing continues at all levels up to
93
+ system testing.
94
+
95
+ ### Upgrade Path
96
+
97
+ It is expected that the development environment will use a Ruby shell while
98
+ larger scale production will use a C shell. That doesn't mean moving to a C
99
+ WAB shell is necessary but it can be used if needed.
100
+
101
+ ## Best for Purpose
102
+
103
+ Ruby is appropriate for the business logic expected in the Controller in the
104
+ MVC model but there are no advantages to using Ruby to form HTML pages for the
105
+ View. JavaScript, HTML, and CSS are a better choice. Along similar lines,
106
+ there is no advantage of using Ruby to write the data store or for that matter
107
+ using Ruby to convert data into database calls. In the development shell it is
108
+ fine but the option to use another language should be available for
109
+ performance reasons. That allows the data store to be a service independent of
110
+ the Ruby code.
data/pages/Plan.md ADDED
@@ -0,0 +1,11 @@
1
+ # Plan
2
+
3
+ More details will be added here as progress continues. For now the hight level plan is:
4
+
5
+ - Define APIs
6
+ - View API
7
+ - Model/Store API
8
+ - Structure Ruby Framework
9
+ - Embedded Glue layer
10
+ - External Glue layer
11
+
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wabur
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0d1
5
+ platform: ruby
6
+ authors:
7
+ - Peter Ohler
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-06-03 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: 'Web Application Builder '
14
+ email: peter@ohler.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files:
18
+ - README.md
19
+ - pages/Architecture.md
20
+ - pages/Goals.md
21
+ - pages/Plan.md
22
+ files:
23
+ - LICENSE
24
+ - README.md
25
+ - lib/wab.rb
26
+ - lib/wab/controller.rb
27
+ - lib/wab/data.rb
28
+ - lib/wab/model.rb
29
+ - lib/wab/shell.rb
30
+ - lib/wab/version.rb
31
+ - lib/wab/view.rb
32
+ - pages/Architecture.md
33
+ - pages/Goals.md
34
+ - pages/Plan.md
35
+ homepage: http://github.com/ohler55/wabur
36
+ licenses:
37
+ - MIT
38
+ metadata: {}
39
+ post_install_message:
40
+ rdoc_options:
41
+ - "--title"
42
+ - WABuR
43
+ - "--main"
44
+ - README.md
45
+ - "--private"
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">"
56
+ - !ruby/object:Gem::Version
57
+ version: 1.3.1
58
+ requirements: []
59
+ rubyforge_project: wabur
60
+ rubygems_version: 2.6.11
61
+ signing_key:
62
+ specification_version: 4
63
+ summary: Web Application Builder
64
+ test_files: []