wabur 0.1.0d1

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 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: []