nali 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/Gemfile +1 -2
  2. data/LICENSE.txt +1 -1
  3. data/Rakefile +0 -1
  4. data/bin/nali +13 -0
  5. data/lib/assets/javascripts/nali/application.js.coffee +1 -1
  6. data/lib/assets/javascripts/nali/connection.js.coffee +2 -2
  7. data/lib/assets/javascripts/nali/model.js.coffee +41 -15
  8. data/lib/generator/Gemfile +11 -0
  9. data/lib/generator/Rakefile +3 -0
  10. data/lib/generator/app/assets/javascripts/application.js.coffee +6 -0
  11. data/lib/generator/app/assets/javascripts/controllers/homes.js.coffee +6 -0
  12. data/lib/generator/app/assets/javascripts/models/home.js.coffee +3 -0
  13. data/lib/generator/app/assets/javascripts/views/home/index.js.coffee +1 -0
  14. data/lib/generator/app/assets/stylesheets/application.css.sass +4 -0
  15. data/lib/generator/app/assets/stylesheets/home/index.css.sass +1 -0
  16. data/lib/generator/app/assets/stylesheets/notices/error.css.sass +11 -0
  17. data/lib/generator/app/assets/stylesheets/notices/info.css.sass +11 -0
  18. data/lib/generator/app/assets/stylesheets/notices/warning.css.sass +11 -0
  19. data/lib/generator/app/clients.rb +19 -0
  20. data/lib/generator/app/models/access.yml +0 -0
  21. data/lib/generator/app/templates/application.html.erb +11 -0
  22. data/lib/generator/app/templates/home/index.html +0 -0
  23. data/lib/generator/app/templates/notice/error.html +1 -0
  24. data/lib/generator/app/templates/notice/info.html +1 -0
  25. data/lib/generator/app/templates/notice/warning.html +1 -0
  26. data/lib/generator/config/application.rb +11 -0
  27. data/lib/generator/config/database.yml +17 -0
  28. data/lib/generator/config/environments/development.rb +13 -0
  29. data/lib/generator/config/environments/development.rb~ +32 -0
  30. data/lib/generator/config/environments/production.rb +11 -0
  31. data/lib/generator/config/environments/production.rb~ +80 -0
  32. data/lib/generator/config/environments/test.rb +11 -0
  33. data/lib/generator/config.ru +3 -0
  34. data/lib/nali/application.rb +12 -40
  35. data/lib/nali/clients.rb +40 -0
  36. data/lib/nali/connection.rb +4 -4
  37. data/lib/nali/controller.rb +33 -17
  38. data/lib/nali/extensions.rb +18 -1
  39. data/lib/nali/generator.rb +114 -0
  40. data/lib/nali/model.rb +41 -23
  41. data/lib/nali/path.rb +7 -0
  42. data/lib/nali/version.rb +3 -1
  43. data/lib/nali.rb +2 -9
  44. metadata +37 -38
data/Gemfile CHANGED
@@ -1,4 +1,3 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- # Specify your gem's dependencies in nali.gemspec
4
- gemspec
3
+ gemspec
data/LICENSE.txt CHANGED
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
19
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
20
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
21
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -1 +0,0 @@
1
- require "bundler/gem_tasks"
data/bin/nali ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'nali/extensions'
4
+ require 'nali/version'
5
+ require 'nali/generator'
6
+ require 'nali/path'
7
+
8
+ if ['--version', '-v'].include?(ARGV.first)
9
+ puts "Nali #{Nali::VERSION}"
10
+ exit(0)
11
+ end
12
+
13
+ Nali::Generator.new ARGV
@@ -22,6 +22,6 @@ Nali.extend Application:
22
22
  unless @titleBox
23
23
  @_( '<title>' ).appendTo 'head' unless @_( 'head title' ).lenght
24
24
  @titleBox = @_ 'head title'
25
- @titleBox.text @title
25
+ @titleBox[0].innerText = @title
26
26
  @trigger 'update.title'
27
27
  @
@@ -38,12 +38,12 @@ Nali.extend Connection:
38
38
  @
39
39
 
40
40
  success: ( message ) ->
41
- @journal[ message.journal_id ].success message.params
41
+ @journal[ message.journal_id ].success? message.params
42
42
  delete @journal[ message.journal_id ]
43
43
  @
44
44
 
45
45
  failure: ( message ) ->
46
- @journal[ message.journal_id ].failure message.params
46
+ @journal[ message.journal_id ].failure? message.params
47
47
  delete @journal[ message.journal_id ]
48
48
  @
49
49
 
@@ -33,12 +33,9 @@ Nali.extend Model:
33
33
  @noticesWait.splice @noticesWait.indexOf( item ), 1
34
34
  @
35
35
 
36
- force: ( attributes = {} ) ->
37
- ( attributes = @copy attributes ).id ?= null
38
- for name, value of @attributes when not ( name of attributes )
39
- if value instanceof Object
40
- attributes[ name ] = if value.default? then value.default else null
41
- else attributes[ name ] = value or null
36
+ force: ( params = {} ) ->
37
+ attributes = @default_attributes()
38
+ attributes[ name ] = value for name, value of params
42
39
  attributes[ name ] = @normalizeValue value for name, value of attributes
43
40
  @clone( attributes: attributes ).accessing()
44
41
 
@@ -48,8 +45,8 @@ Nali.extend Model:
48
45
  @
49
46
 
50
47
  save: ( success, failure ) ->
51
- if @isValid()?
52
- @query "#{ @sysname.lowercase() }s.save", @attributes, #=> success? @
48
+ if @isValid()
49
+ @query "#{ @sysname.lowercase() }s.save", @attributes,
53
50
  ( { attributes, created, updated } ) =>
54
51
  @update( attributes, updated, created ).write()
55
52
  success? @
@@ -110,7 +107,7 @@ Nali.extend Model:
110
107
 
111
108
  update_attribute: ( name, value ) ->
112
109
  value = @normalizeValue value
113
- if @attributes[ name ] isnt value and @isValidAttributeValue( name, value )?
110
+ if @attributes[ name ] isnt value and @isValidAttributeValue( name, value )
114
111
  @attributes[ name ] = value
115
112
  @[ 'onUpdate' + name.capitalize() ]?()
116
113
  @trigger "update.#{ name }", @
@@ -129,19 +126,34 @@ Nali.extend Model:
129
126
  collection.add @build attributes
130
127
  @select filters
131
128
  collection
129
+
130
+ # работа с аттрибутами
131
+
132
+ default_attributes: ->
133
+ # возвращает объект аттрибутов по умолчанию
134
+ attributes = id: null
135
+ for name, value of @attributes
136
+ if value instanceof Object
137
+ attributes[ name ] = if value.default? then value.default else null
138
+ else attributes[ name ] = value
139
+ attributes
132
140
 
133
141
  normalizeValue: ( value ) ->
142
+ # приводит значения к нормальному виду, если в строке только числа - преобразуется к числу
143
+ # т.е. строка '123' становится числом 123, '123.5' становится 123.5, а '123abc' остается строкой
134
144
  if typeof value is 'string'
135
145
  value = "#{ value }".trim()
136
- if value is ( ( correct = parseInt( value ) ) + '' ) then correct else value
146
+ if value is ( ( correct = parseFloat( value ) ) + '' ) then correct else value
137
147
  else value
138
148
 
139
149
  isCorrect: ( filters = {} ) ->
150
+ # проверяет соответствие аттрибутов модели определенному набору фильтров, возвращает true либо false
140
151
  return false unless Object.keys( filters ).length
141
152
  return false for name, filter of filters when not @isCorrectAttribute @attributes[ name ], filter
142
153
  return true
143
154
 
144
- isCorrectAttribute: ( attribute, filter ) ->
155
+ isCorrectAttribute: ( attribute, filter ) ->
156
+ # проверяет соответствие аттрибута модели определенному фильтру, возвращает true либо false
145
157
  return false unless attribute
146
158
  if filter instanceof RegExp
147
159
  filter.test attribute
@@ -153,19 +165,24 @@ Nali.extend Model:
153
165
  attribute.toString() in filter or parseInt( attribute ) in filter
154
166
  else false
155
167
 
168
+ # работа со связями
169
+
156
170
  setRelations: ->
171
+ # устанавливает геттеры к объектам связанным с моделью
157
172
  @belongsToRelation attribute for attribute of @attributes when /_id$/.test attribute
158
173
  @hasOneRelation attribute for attribute in [].concat @hasOne
159
174
  @hasManyRelation attribute for attribute in [].concat @hasMany
160
175
  @
161
176
 
162
177
  belongsToRelation: ( attribute ) ->
178
+ # устанавливает геттер типа belongs_to возвращающий связанную модель
163
179
  name = attribute.replace '_id', ''
164
180
  model = @Model.extensions[ name.capitalize() ]
165
181
  @getter name, => model.find @[ attribute ]
166
182
  @
167
183
 
168
184
  hasOneRelation: ( name ) ->
185
+ # устанавливает геттер типа has_one возвращающий связанную модель
169
186
  @getter name, =>
170
187
  delete @[ name ]
171
188
  ( filters = {} )[ "#{ @sysname.lowercase() }_id" ] = @id
@@ -175,13 +192,17 @@ Nali.extend Model:
175
192
  @
176
193
 
177
194
  hasManyRelation: ( name ) ->
195
+ # устанавливает геттер типа has_many возвращающий коллекцию связанных моделей
178
196
  @getter name, =>
179
197
  delete @[ name ]
180
198
  ( filters = {} )[ "#{ @sysname.lowercase() }_id" ] = @id
181
199
  @[ name ] = @Model.extensions[ name[ ...-1 ].capitalize() ].where filters
182
200
  @
183
201
 
202
+ # работа с видами
203
+
184
204
  view: ( name ) ->
205
+ # приводит сокращенное имя к полному и возвращает объект вида, либо новый, либо ранее созданный
185
206
  name = @sysname + name.camelcase().capitalize() unless @View.extensions[ name ]?
186
207
  unless ( view = ( @views ?= {} )[ name ] )?
187
208
  if ( view = @View.extensions[ name ] )?
@@ -190,9 +211,14 @@ Nali.extend Model:
190
211
  view
191
212
 
192
213
  show: ( name, insertTo ) ->
214
+ # вставляет html-код вида в указанное место ( это может быть селектор, html-элемент или ничего - тогда
215
+ # вставка произойдет в элемент указанный в самом виде либо в элемент приложения )
216
+ # функция возвращает объект вида при успехе либо null при неудаче
193
217
  if ( view = @view( name ) )? then view.show insertTo else null
194
218
 
195
219
  hide: ( name ) ->
220
+ # удаляет html-код вида со страницы
221
+ # функция возвращает объект вида при успехе либо null при неудаче
196
222
  if ( view = @view( name ) )? then view.hide() else null
197
223
 
198
224
  # валидации
@@ -220,18 +246,18 @@ Nali.extend Model:
220
246
 
221
247
  isValid: ->
222
248
  # проверяет валидна ли модель, вызывается перед сохранением модели на сервер если модель валидна,
223
- # то вызов model.isValid()? вернет true, иначе false
224
- return null for name, value of @attributes when not @isValidAttributeValue( name, value )?
249
+ # то вызов model.isValid() вернет true, иначе false
250
+ return false for name, value of @attributes when not @isValidAttributeValue( name, value )
225
251
  true
226
252
 
227
253
  isValidAttributeValue: ( name, value ) ->
228
254
  # проверяет валидно ли значение для определенного атрибута модели, вызывается при проверке
229
- # валидности модели, а также в методе update() перед изменением значения атрибута, если значение
255
+ # валидности модели, а также в методе update_attribute() перед изменением значения атрибута, если значение
230
256
  # валидно то вызов model.isValidAttributeValue( name, value )? вернет true, иначе false
231
257
  for validation, tester of @validations when ( filter = @::attributes[ name ]?[ validation ] )?
232
258
  unless tester.call @, value, filter
233
259
  console.warn 'Attribute %s of model %O has not validate %s', name, @, validation
234
260
  for type in [ 'info', 'warning', 'error' ] when ( message = @::attributes[ name ][ type ] )?
235
261
  @Notice[ type ] message: message
236
- return null
262
+ return false
237
263
  true
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'nali'
4
+
5
+ gem 'sqlite3'
6
+
7
+ gem 'yui-compressor'
8
+
9
+ gem 'uglifier'
10
+
11
+ gem 'debugger'
@@ -0,0 +1,3 @@
1
+ require './config/application'
2
+
3
+ Nali::Application.tasks
@@ -0,0 +1,6 @@
1
+ #= require nali
2
+ #= require_tree .
3
+
4
+ Nali.Application.run
5
+ defaultUrl: 'home'
6
+ notFoundUrl: 'home'
@@ -0,0 +1,6 @@
1
+ Nali.Controller.extend Homes:
2
+
3
+ actions:
4
+ default: 'index'
5
+
6
+ index: ( collection ) ->
@@ -0,0 +1,3 @@
1
+ Nali.Model.extend Home:
2
+
3
+ forced: true
@@ -0,0 +1 @@
1
+ Nali.View.extend HomeIndex: {}
@@ -0,0 +1,4 @@
1
+ /*
2
+ *= require_self
3
+ *= require_tree .
4
+ */
@@ -0,0 +1,11 @@
1
+ .NoticeError
2
+ position: absolute
3
+ z-index: 99
4
+ bottom: 1rem
5
+ right: 2rem
6
+ width: 55%
7
+ background: rgba(35, 35, 35, 0.95)
8
+ border-radius: 0.3rem
9
+ box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.7)
10
+ color: #F75E4E
11
+ padding: 1.3rem
@@ -0,0 +1,11 @@
1
+ .NoticeInfo
2
+ position: absolute
3
+ z-index: 99
4
+ bottom: 1rem
5
+ right: 2rem
6
+ width: 55%
7
+ background: rgba(35, 35, 35, 0.95)
8
+ border-radius: 0.3rem
9
+ box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.7)
10
+ color: #58EB96
11
+ padding: 1.3rem
@@ -0,0 +1,11 @@
1
+ .NoticeWarning
2
+ position: absolute
3
+ z-index: 99
4
+ bottom: 1rem
5
+ right: 2rem
6
+ width: 55%
7
+ background: rgba(35, 35, 35, 0.95)
8
+ border-radius: 0.3rem
9
+ box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.7)
10
+ color: #FED93A
11
+ padding: 1.3rem
@@ -0,0 +1,19 @@
1
+ module Nali
2
+
3
+ module Clients
4
+
5
+ def self.client_connected( client )
6
+
7
+ end
8
+
9
+ def self.on_message( client, message )
10
+
11
+ end
12
+
13
+ def self.client_disconnected( client )
14
+
15
+ end
16
+
17
+ end
18
+
19
+ end
File without changes
@@ -0,0 +1,11 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
5
+ <%= stylesheet_tag 'application' %>
6
+ <%= templates_tags %>
7
+ <%= javascript_tag 'application' %>
8
+ </head>
9
+ <body>
10
+ </body>
11
+ </html>
File without changes
@@ -0,0 +1 @@
1
+ { @message }
@@ -0,0 +1 @@
1
+ { @message }
@@ -0,0 +1 @@
1
+ { @message }
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ Bundler.require
4
+
5
+ module Nali
6
+
7
+ class Application
8
+
9
+ end
10
+
11
+ end
@@ -0,0 +1,17 @@
1
+ development:
2
+ adapter: sqlite3
3
+ database: db/development.sqlite3
4
+ pool: 5
5
+ timeout: 5000
6
+
7
+ test:
8
+ adapter: sqlite3
9
+ database: db/test.sqlite3
10
+ pool: 5
11
+ timeout: 5000
12
+
13
+ production:
14
+ adapter: sqlite3
15
+ database: db/production.sqlite3
16
+ pool: 5
17
+ timeout: 5000
@@ -0,0 +1,13 @@
1
+ Nali::Application.configure :development do |config|
2
+
3
+ # config.assets_digest = true
4
+
5
+ config.assets_debug = true
6
+
7
+ # config.assets.js_compressor = Uglifier.new( mangle: true )
8
+
9
+ # config.assets.css_compressor = YUI::CssCompressor.new
10
+
11
+ ActiveRecord::Base.logger = false #Logger.new STDOUT
12
+
13
+ end
@@ -0,0 +1,32 @@
1
+ Evo::Application.configure do
2
+ # Settings specified here will take precedence over those in config/application.rb.
3
+
4
+ # In the development environment your application's code is reloaded on
5
+ # every request. This slows down response time but is perfect for development
6
+ # since you don't have to restart the web server when you make code changes.
7
+ config.cache_classes = false
8
+
9
+ # Do not eager load code on boot.
10
+ config.eager_load = false
11
+
12
+ # Show full error reports and disable caching.
13
+ config.consider_all_requests_local = true
14
+ config.action_controller.perform_caching = false
15
+
16
+ config.middleware.delete Rack::Lock
17
+
18
+ # Don't care if the mailer can't send.
19
+ config.action_mailer.raise_delivery_errors = false
20
+
21
+ # Print deprecation notices to the Rails logger.
22
+ config.active_support.deprecation = :log
23
+
24
+ # Raise an error on page load if there are pending migrations
25
+ config.active_record.migration_error = :page_load
26
+
27
+ # Debug mode disables concatenation and preprocessing of assets.
28
+ # This option may cause significant delays in view rendering with a large
29
+ # number of complex assets.
30
+ config.assets.debug = true
31
+ config.log_level = :error
32
+ end
@@ -0,0 +1,11 @@
1
+ Nali::Application.configure :production do |config|
2
+
3
+ config.assets_digest = true
4
+
5
+ # config.assets_debug = true
6
+
7
+ config.assets.js_compressor = Uglifier.new( mangle: true )
8
+
9
+ config.assets.css_compressor = YUI::CssCompressor.new
10
+
11
+ end
@@ -0,0 +1,80 @@
1
+ Evo::Application.configure do
2
+ # Settings specified here will take precedence over those in config/application.rb.
3
+
4
+ # Code is not reloaded between requests.
5
+ config.cache_classes = true
6
+
7
+ # Eager load code on boot. This eager loads most of Rails and
8
+ # your application in memory, allowing both thread web servers
9
+ # and those relying on copy on write to perform better.
10
+ # Rake tasks automatically ignore this option for performance.
11
+ config.eager_load = true
12
+
13
+ # Full error reports are disabled and caching is turned on.
14
+ config.consider_all_requests_local = false
15
+ config.action_controller.perform_caching = true
16
+
17
+ # Enable Rack::Cache to put a simple HTTP cache in front of your application
18
+ # Add `rack-cache` to your Gemfile before enabling this.
19
+ # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid.
20
+ # config.action_dispatch.rack_cache = true
21
+
22
+ # Disable Rails's static asset server (Apache or nginx will already do this).
23
+ config.serve_static_assets = false
24
+
25
+ # Compress JavaScripts and CSS.
26
+ config.assets.js_compressor = :uglifier
27
+ # config.assets.css_compressor = :sass
28
+
29
+ # Do not fallback to assets pipeline if a precompiled asset is missed.
30
+ config.assets.compile = false
31
+
32
+ # Generate digests for assets URLs.
33
+ config.assets.digest = true
34
+
35
+ # Version of your assets, change this if you want to expire all your assets.
36
+ config.assets.version = '1.0'
37
+
38
+ # Specifies the header that your server uses for sending files.
39
+ # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
40
+ # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
41
+
42
+ # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
43
+ # config.force_ssl = true
44
+
45
+ # Set to :debug to see everything in the log.
46
+ config.log_level = :info
47
+
48
+ # Prepend all log lines with the following tags.
49
+ # config.log_tags = [ :subdomain, :uuid ]
50
+
51
+ # Use a different logger for distributed setups.
52
+ # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
53
+
54
+ # Use a different cache store in production.
55
+ # config.cache_store = :mem_cache_store
56
+
57
+ # Enable serving of images, stylesheets, and JavaScripts from an asset server.
58
+ # config.action_controller.asset_host = "http://assets.example.com"
59
+
60
+ # Precompile additional assets.
61
+ # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
62
+ # config.assets.precompile += %w( search.js )
63
+
64
+ # Ignore bad email addresses and do not raise email delivery errors.
65
+ # Set this to true and configure the email server for immediate delivery to raise delivery errors.
66
+ # config.action_mailer.raise_delivery_errors = false
67
+
68
+ # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
69
+ # the I18n.default_locale when a translation can not be found).
70
+ config.i18n.fallbacks = true
71
+
72
+ # Send deprecation notices to registered listeners.
73
+ config.active_support.deprecation = :notify
74
+
75
+ # Disable automatic flushing of the log to improve performance.
76
+ # config.autoflush_log = false
77
+
78
+ # Use default logging formatter so that PID and timestamp are not suppressed.
79
+ config.log_formatter = ::Logger::Formatter.new
80
+ end
@@ -0,0 +1,11 @@
1
+ Nali::Application.configure :test do |config|
2
+
3
+ # config.assets_digest = true
4
+
5
+ # config.assets_debug = true
6
+
7
+ # config.assets.js_compressor = Uglifier.new( mangle: true )
8
+
9
+ # config.assets.css_compressor = YUI::CssCompressor.new
10
+
11
+ end
@@ -0,0 +1,3 @@
1
+ require './config/application'
2
+
3
+ run Nali::Application.initialize!
@@ -19,9 +19,10 @@ module Nali
19
19
  require File.join( root, 'config/environments', environment.to_s )
20
20
 
21
21
  configure do
22
+
22
23
  assets.cache = Sprockets::Cache::FileStore.new File.join( root, 'tmp/cache' )
23
24
 
24
- assets.append_path File.join( Nali.gem_path, 'lib/assets/javascripts' )
25
+ assets.append_path File.join( Nali.path, 'assets/javascripts' )
25
26
 
26
27
  %w( app/templates app/assets/stylesheets app/assets/javascripts lib/assets/stylesheets
27
28
  lib/assets/javascripts vendor/assets/stylesheets vendor/assets/javascripts
@@ -46,53 +47,24 @@ module Nali
46
47
  settings.assets[ 'application.html' ]
47
48
  else
48
49
  request.websocket do |client|
49
- client.onopen { onopen client }
50
- client.onmessage { |message| onmessage( client, JSON.parse( message ).keys_to_sym! ) }
51
- client.onclose { onclose client }
50
+ client.onopen { Nali::Clients.on_client_connected client }
51
+ client.onmessage { |message| Nali::Clients.on_received_message( client, JSON.parse( message ).keys_to_sym! ) }
52
+ client.onclose { Nali::Clients.on_client_disconnected client }
52
53
  end
53
54
  end
54
55
  end
55
56
 
56
- def onopen( client )
57
- clients << client
58
- client_connected client
59
- end
60
-
61
- def onmessage( client, message )
62
- if controller = Object.const_get( message[ :controller ].capitalize + 'Controller' )
63
- controller = controller.new( client, message )
64
- if controller.methods.include?( action = message[ :action ].to_sym )
65
- controller.send action
66
- else puts "Action #{ action } not exists in #{ controller }" end
67
- else puts "Controller #{ controller } not exists" end
68
- on_message client, message
69
- end
70
-
71
- def onclose( client )
72
- clients.delete client
73
- client_disconnected client
74
- end
75
-
76
- def client_connected( client )
77
- end
78
-
79
- def on_message( client, message )
80
- end
81
-
82
- def client_disconnected( client )
83
- end
84
-
85
- def clients
86
- self.class.clients
87
- end
88
-
89
- def self.clients
90
- @@clients ||= []
57
+ def self.access_options
58
+ if settings.environment == :development
59
+ YAML.load_file( File.join( root, 'app/models/access.yml' ) ).keys_to_sym!
60
+ else
61
+ @access_options ||= YAML.load_file( File.join( root, 'app/models/access.yml' ) ).keys_to_sym!
62
+ end
91
63
  end
92
64
 
93
65
  def self.initialize!
94
66
  Dir[ File.join( root, 'lib/*/**/*.rb' ) ].each { |file| require( file ) }
95
- Dir[ File.join( root, 'app/*/**/*.rb' ) ].each { |file| require( file ) }
67
+ Dir[ File.join( root, 'app/**/*.rb' ) ].each { |file| require( file ) }
96
68
  Dir[ File.join( root, 'vendor/*/**/*.rb' ) ].each { |file| require( file ) }
97
69
  require File.join( root, 'config/application' )
98
70
  self
@@ -0,0 +1,40 @@
1
+ module Nali
2
+
3
+ module Clients
4
+
5
+ def self.clients
6
+ @@clients ||= []
7
+ end
8
+
9
+ def self.on_client_connected( client )
10
+ clients << client
11
+ client_connected client
12
+ end
13
+
14
+ def self.on_received_message( client, message )
15
+ if controller = Object.const_get( message[ :controller ].capitalize + 'Controller' )
16
+ controller = controller.new( client, message )
17
+ if controller.methods.include?( action = message[ :action ].to_sym )
18
+ controller.send action
19
+ else puts "Action #{ action } not exists in #{ controller }" end
20
+ else puts "Controller #{ controller } not exists" end
21
+ on_message client, message
22
+ end
23
+
24
+ def self.on_client_disconnected( client )
25
+ clients.delete client
26
+ client_disconnected client
27
+ end
28
+
29
+ def self.client_connected( client )
30
+ end
31
+
32
+ def self.on_message( client, message )
33
+ end
34
+
35
+ def self.client_disconnected( client )
36
+ end
37
+
38
+ end
39
+
40
+ end
@@ -1,7 +1,6 @@
1
1
  module EventMachine
2
2
  module WebSocket
3
3
  class Connection
4
-
5
4
 
6
5
  def filters( model_name )
7
6
  @filters ||= {}
@@ -60,10 +59,11 @@ module EventMachine
60
59
  end
61
60
 
62
61
  def sync( model )
63
- if model.sync_access( self ) and ( watch_time( model ) < model.updated_at.to_f or model.destroyed? )
62
+ params, relations = model.get_sync_params( self )
63
+ if not params.empty? and ( watch_time( model ) < model.updated_at.to_f or model.destroyed? )
64
64
  watch_time_up model
65
- model.get_sync_models( self ).each { |relation| sync relation } unless model.destroyed?
66
- send_json( { action: 'sync', params: model.get_sync_params( self ) } )
65
+ relations.each { |relation| sync relation }
66
+ send_json action: 'sync', params: params
67
67
  end
68
68
  end
69
69
 
@@ -11,25 +11,34 @@ module Nali
11
11
  end
12
12
 
13
13
  def clients
14
- Nali::Application.clients
14
+ Nali::Clients.clients
15
15
  end
16
16
 
17
17
  def save
18
- if params[ :id ]
19
- if model = model_class.find_by_id( params[ :id ] )
20
- save_success( model ) if model.update_attributes( params )
21
- end
22
- else
23
- if ( model = model_class.new( params ) ).valid?
24
- save_success( model ) if model.save
25
- end
18
+ params[ :id ] ? update : create
19
+ end
20
+
21
+ def create
22
+ model = model_class.new params
23
+ model.access_action( :create, client ) do |options|
24
+ permit_params options
25
+ if ( model = model_class.new( params ) ).save
26
+ trigger_success model.get_sync_params( client )[0]
27
+ model.sync client
28
+ else trigger_failure end
26
29
  end
27
30
  end
28
31
 
29
- def save_success( model )
30
- on_save( model ) if self.methods.include?( :on_save )
31
- trigger_success model.get_sync_params( client )
32
- model.sync client
32
+ def update
33
+ if model = model_class.find_by_id( params[ :id ] )
34
+ model.access_action( :update, client ) do |options|
35
+ permit_params options
36
+ if model.update( params )
37
+ trigger_success model.get_sync_params( client )[0]
38
+ model.sync client
39
+ else trigger_failure end
40
+ end
41
+ end
33
42
  end
34
43
 
35
44
  def select
@@ -39,10 +48,12 @@ module Nali
39
48
 
40
49
  def destroy
41
50
  if model = model_class.find_by_id( params[ :id ] )
42
- on_destroy( model ) if self.methods.include?( :on_destroy )
43
- model.destroy()
44
- model.sync
45
- end
51
+ model.access_action( :destroy, client ) do |options|
52
+ model.destroy()
53
+ trigger_success model.id
54
+ model.sync
55
+ end
56
+ else trigger_failure end
46
57
  end
47
58
 
48
59
  def trigger_success( params = nil )
@@ -55,6 +66,11 @@ module Nali
55
66
 
56
67
  private
57
68
 
69
+ def permit_params( filter )
70
+ params.keys.each { |key| params.delete( key ) unless filter.include?( key ) }
71
+ params
72
+ end
73
+
58
74
  def model_class
59
75
  Object.const_get model_name
60
76
  end
@@ -2,10 +2,27 @@ class Object
2
2
 
3
3
  def keys_to_sym!
4
4
  self.keys.each do |key|
5
- self[ key ].keys_to_sym! if self[ key ].is_a?( Hash ) || self[ key ].is_a?( Array )
5
+ self[ key ].keys_to_sym! if self[ key ].is_a?( Hash )
6
6
  self[ ( key.to_sym rescue key ) ] = self.delete( key )
7
7
  end
8
8
  self
9
9
  end
10
10
 
11
+ end
12
+
13
+ class String
14
+
15
+ def underscore!
16
+ gsub!(/(.)([A-Z])/,'\1_\2')
17
+ downcase!
18
+ end
19
+
20
+ def underscore
21
+ dup.tap { |s| s.underscore! }
22
+ end
23
+
24
+ def capitalize_first
25
+ dup.tap { |s| s[0] = s[0].capitalize }
26
+ end
27
+
11
28
  end
@@ -0,0 +1,114 @@
1
+ module Nali
2
+
3
+ class Generator
4
+
5
+ def initialize( args )
6
+ if [ 'app', 'application' ].include?( args.first )
7
+ if args[1] then create_application args[1]
8
+ else puts 'Enter a name for the application' end
9
+ end
10
+
11
+ if [ 'm', 'model' ].include?( args.first )
12
+ if args[1] then create_model args[1]
13
+ else puts 'Enter a name for the model' end
14
+ end
15
+
16
+ if [ 'v', 'view' ].include?( args.first )
17
+ if args[1] then create_view args[1]
18
+ else puts 'Enter a name for the view' end
19
+ end
20
+
21
+ end
22
+
23
+ def create_application( name )
24
+ source_path = File.join( Nali.path, 'generator/.' )
25
+ target_path = File.join( Dir.pwd, name )
26
+ FileUtils.cp_r source_path, target_path
27
+ dirs = []
28
+ dirs << File.join( target_path, "app/controllers" )
29
+ dirs << File.join( target_path, "db" )
30
+ dirs << File.join( target_path, "db/migrate" )
31
+ dirs << File.join( target_path, "lib" )
32
+ dirs << File.join( target_path, "public" )
33
+ dirs << File.join( target_path, "tmp" )
34
+ dirs << File.join( target_path, "vendor" )
35
+ dirs.each { |path| Dir.mkdir( path ) unless Dir.exists?( path ) }
36
+ puts "Application #{ name } created"
37
+ end
38
+
39
+ def create_model( name )
40
+ if Dir.exists?( File.join( Dir.pwd, 'app' ) )
41
+ filename = name.underscore
42
+ classname = name.capitalize_first
43
+ File.open( File.join( Dir.pwd, "app/assets/javascripts/models/#{ filename }.js.coffee" ), 'w' ) do |f|
44
+ f.write( "Nali.Model.extend #{ classname }: {}" )
45
+ end
46
+ File.open( File.join( Dir.pwd, "app/assets/javascripts/controllers/#{ filename }s.js.coffee" ), 'w' ) do |f|
47
+ f.write( "Nali.Controller.extend #{ classname }s: {}" )
48
+ end
49
+ File.open( File.join( Dir.pwd, "app/models/#{ filename }.rb" ), 'w' ) do |f|
50
+ f.write(
51
+ "class #{ classname } < ActiveRecord::Base
52
+
53
+ include Nali::Model
54
+
55
+ end"
56
+ )
57
+ end
58
+ File.open( File.join( Dir.pwd, "app/controllers/#{ filename }s_controller.rb" ), 'w' ) do |f|
59
+ f.write(
60
+ "class #{ classname }sController
61
+
62
+ include Nali::Controller
63
+
64
+ end"
65
+ )
66
+ end
67
+ File.open( File.join( Dir.pwd, "app/models/access.yml" ), 'a' ) do |f|
68
+ f.write(
69
+ "#{ classname }:
70
+ create:
71
+ read:
72
+ update:
73
+ destroy:
74
+
75
+
76
+ "
77
+ )
78
+ end
79
+ FileUtils.rm_rf( File.join( Dir.pwd, "tmp/cache" ) )
80
+ puts "Created: app/assets/javascripts/models/#{ filename }.js.coffee"
81
+ puts "Created: app/assets/javascripts/controllers/#{ filename }s.js.coffee"
82
+ puts "Created: app/models/#{ filename }.rb"
83
+ puts "Created: app/controllers/#{ filename }s_controller.rb"
84
+ puts "Updated: app/models/access.yml"
85
+ else puts 'Please go to the application folder' end
86
+ end
87
+
88
+ def create_view( name )
89
+ if Dir.exists?( File.join( Dir.pwd, 'app' ) )
90
+ dirname, *filename = name.underscore.split( '_' )
91
+ filename = filename.join( '_' )
92
+ classname = name.capitalize_first
93
+ dirs = []
94
+ dirs << File.join( Dir.pwd, "app/assets/javascripts/views/#{ dirname }" )
95
+ dirs << File.join( Dir.pwd, "app/assets/stylesheets/#{ dirname }" )
96
+ dirs << File.join( Dir.pwd, "app/templates/#{ dirname }" )
97
+ dirs.each { |path| Dir.mkdir( path ) unless Dir.exists?( path ) }
98
+ File.open( File.join( Dir.pwd, "app/assets/javascripts/views/#{ dirname }/#{ filename }.js.coffee" ), 'w' ) do |f|
99
+ f.write( "Nali.View.extend #{ classname }: {}" )
100
+ end
101
+ File.open( File.join( Dir.pwd, "app/assets/stylesheets/#{ dirname }/#{ filename }.css.sass" ), 'w' ) do |f|
102
+ f.write( ".#{ classname }" )
103
+ end
104
+ File.open( File.join( Dir.pwd, "app/templates/#{ dirname }/#{ filename }.html" ), 'w' ) {}
105
+ FileUtils.rm_rf( File.join( Dir.pwd, "tmp/cache" ) )
106
+ puts "Created: app/assets/javascripts/views/#{ dirname }/#{ filename }.js.coffee"
107
+ puts "Created: app/assets/stylesheets/#{ dirname }/#{ filename }.css.sass"
108
+ puts "Created: app/templates/#{ dirname }/#{ filename }.html"
109
+ else puts 'Please go to the application folder' end
110
+ end
111
+
112
+ end
113
+
114
+ end
data/lib/nali/model.rb CHANGED
@@ -1,37 +1,49 @@
1
1
  module Nali
2
2
 
3
3
  module Model
4
-
5
- def sync_access( client )
6
- true
7
- end
8
-
9
- def sync_models( client )
10
- []
11
- end
12
-
13
- def sync_params( client )
14
- {}
4
+
5
+ def access_level( client )
6
+ :default
15
7
  end
16
8
 
17
- def get_sync_models( client )
18
- ( [] << sync_models( client ) ).flatten.compact
9
+ def access_action( action, client )
10
+ level = self.access_level client
11
+ if access_levels = access_options[ action ] and access_levels.keys.include?( level )
12
+ options = []
13
+ ( [] << access_levels[ level ] ).flatten.compact.each { |option| options << option.to_sym }
14
+ yield options
15
+ end
19
16
  end
20
17
 
21
18
  def get_sync_params( client )
22
- attributes = sync_params( client )
23
- attributes[ :id ] = self.id
24
- {
25
- attributes: attributes,
26
- created: self.created_at.to_f,
27
- updated: self.updated_at.to_f,
28
- sysname: self.class.name,
29
- destroyed: self.destroyed?
30
- }
19
+ params = {}
20
+ relations = []
21
+ access_action( :read, client ) do |options|
22
+ attributes = { id: self.id }
23
+ options.each do |option|
24
+ if self.respond_to?( option )
25
+ value = self.send( option )
26
+ if value.is_a?( ActiveRecord::Associations::CollectionProxy )
27
+ relations << value unless self.destroyed?
28
+ elsif value.is_a?( ActiveRecord::Base )
29
+ relations << value unless self.destroyed?
30
+ attributes[ option.to_s + '_id' ] = value.id
31
+ else
32
+ attributes[ option ] = value
33
+ end
34
+ end
35
+ end
36
+ params[ :attributes ] = attributes
37
+ params[ :sysname ] = self.class.name
38
+ params[ :created ] = self.created_at.to_f
39
+ params[ :updated ] = self.updated_at.to_f
40
+ params[ :destroyed ] = self.destroyed?
41
+ end
42
+ [ params, relations.flatten.compact ]
31
43
  end
32
44
 
33
45
  def clients
34
- Nali::Application.clients
46
+ Nali::Clients.clients
35
47
  end
36
48
 
37
49
  def sync( *watches )
@@ -42,6 +54,12 @@ module Nali
42
54
  def notice( name, params )
43
55
  clients.each { |client| client.notice self, name, params if client.watch?( self ) }
44
56
  end
57
+
58
+ private
59
+
60
+ def access_options
61
+ Nali::Application.access_options[ self.class.name.to_sym ] or {}
62
+ end
45
63
 
46
64
  end
47
65
 
data/lib/nali/path.rb ADDED
@@ -0,0 +1,7 @@
1
+ module Nali
2
+
3
+ def self.path
4
+ @gem_path ||= File.expand_path '..', File.dirname( __FILE__ )
5
+ end
6
+
7
+ end
data/lib/nali/version.rb CHANGED
@@ -1,3 +1,5 @@
1
1
  module Nali
2
- VERSION = "0.1.2"
2
+
3
+ VERSION = '0.1.3'
4
+
3
5
  end
data/lib/nali.rb CHANGED
@@ -7,18 +7,11 @@ require 'sprockets-sass'
7
7
  require 'sprockets-helpers'
8
8
  require 'coffee-script'
9
9
  require 'sass'
10
- require 'sqlite3'
11
-
12
- module Nali
13
-
14
- def self.gem_path
15
- @gem_path ||= File.expand_path '..', File.dirname( __FILE__ )
16
- end
17
-
18
- end
19
10
 
20
11
  require 'nali/extensions'
12
+ require 'nali/path'
21
13
  require 'nali/application'
14
+ require 'nali/clients'
22
15
  require 'nali/connection'
23
16
  require 'nali/controller'
24
17
  require 'nali/model'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nali
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-10-06 00:00:00.000000000 Z
12
+ date: 2014-10-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thin
@@ -171,38 +171,6 @@ dependencies:
171
171
  - - ! '>='
172
172
  - !ruby/object:Gem::Version
173
173
  version: '0'
174
- - !ruby/object:Gem::Dependency
175
- name: sqlite3
176
- requirement: !ruby/object:Gem::Requirement
177
- none: false
178
- requirements:
179
- - - ! '>='
180
- - !ruby/object:Gem::Version
181
- version: '0'
182
- type: :runtime
183
- prerelease: false
184
- version_requirements: !ruby/object:Gem::Requirement
185
- none: false
186
- requirements:
187
- - - ! '>='
188
- - !ruby/object:Gem::Version
189
- version: '0'
190
- - !ruby/object:Gem::Dependency
191
- name: bundler
192
- requirement: !ruby/object:Gem::Requirement
193
- none: false
194
- requirements:
195
- - - ~>
196
- - !ruby/object:Gem::Version
197
- version: '1.3'
198
- type: :development
199
- prerelease: false
200
- version_requirements: !ruby/object:Gem::Requirement
201
- none: false
202
- requirements:
203
- - - ~>
204
- - !ruby/object:Gem::Version
205
- version: '1.3'
206
174
  - !ruby/object:Gem::Dependency
207
175
  name: rake
208
176
  requirement: !ruby/object:Gem::Requirement
@@ -211,7 +179,7 @@ dependencies:
211
179
  - - ! '>='
212
180
  - !ruby/object:Gem::Version
213
181
  version: '0'
214
- type: :development
182
+ type: :runtime
215
183
  prerelease: false
216
184
  version_requirements: !ruby/object:Gem::Requirement
217
185
  none: false
@@ -219,10 +187,11 @@ dependencies:
219
187
  - - ! '>='
220
188
  - !ruby/object:Gem::Version
221
189
  version: '0'
222
- description: Realtime app
190
+ description: Async web framework
223
191
  email:
224
192
  - 4urbanoff@gmail.com
225
- executables: []
193
+ executables:
194
+ - nali
226
195
  extensions: []
227
196
  extra_rdoc_files: []
228
197
  files:
@@ -242,11 +211,41 @@ files:
242
211
  - lib/assets/javascripts/nali/connection.js.coffee
243
212
  - lib/nali/extensions.rb
244
213
  - lib/nali/model.rb
214
+ - lib/nali/clients.rb
245
215
  - lib/nali/controller.rb
216
+ - lib/nali/generator.rb
246
217
  - lib/nali/connection.rb
247
218
  - lib/nali/version.rb
248
219
  - lib/nali/helpers.rb
220
+ - lib/nali/path.rb
249
221
  - lib/nali/application.rb
222
+ - lib/generator/app/assets/javascripts/models/home.js.coffee
223
+ - lib/generator/app/assets/javascripts/views/home/index.js.coffee
224
+ - lib/generator/app/assets/javascripts/controllers/homes.js.coffee
225
+ - lib/generator/app/assets/javascripts/application.js.coffee
226
+ - lib/generator/app/assets/stylesheets/home/index.css.sass
227
+ - lib/generator/app/assets/stylesheets/notices/info.css.sass
228
+ - lib/generator/app/assets/stylesheets/notices/error.css.sass
229
+ - lib/generator/app/assets/stylesheets/notices/warning.css.sass
230
+ - lib/generator/app/assets/stylesheets/application.css.sass
231
+ - lib/generator/app/models/access.yml
232
+ - lib/generator/app/clients.rb
233
+ - lib/generator/app/templates/application.html.erb
234
+ - lib/generator/app/templates/notice/error.html
235
+ - lib/generator/app/templates/notice/warning.html
236
+ - lib/generator/app/templates/notice/info.html
237
+ - lib/generator/app/templates/home/index.html
238
+ - lib/generator/Rakefile
239
+ - lib/generator/config.ru
240
+ - lib/generator/config/environments/development.rb
241
+ - lib/generator/config/environments/production.rb~
242
+ - lib/generator/config/environments/test.rb
243
+ - lib/generator/config/environments/development.rb~
244
+ - lib/generator/config/environments/production.rb
245
+ - lib/generator/config/database.yml
246
+ - lib/generator/config/application.rb
247
+ - lib/generator/Gemfile
248
+ - bin/nali
250
249
  - LICENSE.txt
251
250
  - Rakefile
252
251
  - Gemfile
@@ -275,5 +274,5 @@ rubyforge_project:
275
274
  rubygems_version: 1.8.25
276
275
  signing_key:
277
276
  specification_version: 3
278
- summary: summary
277
+ summary: Framework for developing async web applications
279
278
  test_files: []