conjoin 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8b692688fd417e4aefb6564c8f6707d06eeb0941
4
- data.tar.gz: 5d0a41377c3344a7d1360f4a3f7857e3eedc5488
3
+ metadata.gz: 4c454413ab5c7c375c051e3ced92551be1712d05
4
+ data.tar.gz: db8a9ed9f764770c4ff4d82b3d3c3a4593c9ba6c
5
5
  SHA512:
6
- metadata.gz: f4036bb8562d6e3618d565d0eb0884250b58e9d14aadebeb72c1e44c941828dd931758f03863b518e83e7e3ae6bd3a5006b607d21caed7555a68a5106be0c857
7
- data.tar.gz: f85401e08c55b7eb488ad148d7fdd11cdf4ddce05eef9997c926ddd5071f65b422e12f790bb12cc359bf92017dc2846c51da75a8cff4ccecaf63a28b2ec5feb0
6
+ metadata.gz: e428284a01f0dd42f77beafb36e214f2e4e4cff749257cca9680ae72565a8fa063927255bd8452fe50f75cc44640ef544e3779131114aba55e5348bbfab843bd
7
+ data.tar.gz: 9578582ec7152be92f90d4d6a6e2d26c300332729ad24504c949030acc92e20ffe54ea40ceb016375e9fee00cf8e64f5bfa61d8e5c358903c903ba4d4551cbf3
data/conjoin.gemspec CHANGED
@@ -18,6 +18,26 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
+ spec.add_dependency "cuba", "~> 3.1.1"
22
+ spec.add_dependency "cuba-sugar"
23
+ spec.add_dependency "rack_csrf", "~> 2.4.0"
24
+ spec.add_dependency "rack-protection", "~> 1.5.2"
25
+ spec.add_dependency "r18n-core"
26
+ spec.add_dependency 'highline', '~> 1.6.11'
27
+ spec.add_dependency "mab"
28
+ spec.add_dependency "tilt"
29
+ spec.add_dependency "sass"
30
+ spec.add_dependency "coffee-script"
31
+ spec.add_dependency "slim"
32
+ spec.add_dependency "mimemagic"
33
+ spec.add_dependency "rake"
34
+ spec.add_dependency "hashie"
35
+ spec.add_dependency "chronic"
36
+ spec.add_dependency "unicorn"
37
+ spec.add_dependency "clap"
38
+ spec.add_dependency "shield"
39
+ spec.add_dependency "better_errors"
40
+
21
41
  spec.add_development_dependency "bundler", "~> 1.3"
22
42
  spec.add_development_dependency "rake"
23
43
  end
data/lib/conjoin.rb CHANGED
@@ -1,5 +1,31 @@
1
1
  require "conjoin/version"
2
+ require "conjoin/recursive_ostruct"
3
+ require "conjoin/middleware"
4
+ require "conjoin/env_string"
5
+ require "conjoin/class_methods"
6
+ require "conjoin/cuba"
2
7
 
3
8
  module Conjoin
4
- # Your code goes here...
9
+ extend ClassMethods
10
+
11
+ if not env.mounted?
12
+ require 'active_record'
13
+ require 'action_mailer'
14
+ require 'slim'
15
+ require "tilt/coffee"
16
+ require "tilt/sass"
17
+ end
18
+
19
+ autoload :ActiveRecord, "conjoin/active_record"
20
+ autoload :Assets , "conjoin/assets"
21
+ autoload :Auth , "conjoin/auth"
22
+ autoload :Environment , "conjoin/environment"
23
+ autoload :FormBuilder , "conjoin/form_builder"
24
+ autoload :I18N , "conjoin/i18n"
25
+ autoload :Widgets , "conjoin/widgets"
26
+ autoload :Csrf , "conjoin/csrf"
27
+ # ActionMailer
28
+ # https://gist.github.com/acwright/1944639
29
+ # DelayedJob
30
+ # https://gist.github.com/robhurring/732327
5
31
  end
@@ -0,0 +1,374 @@
1
+ module Conjoin
2
+ module ActiveRecord
3
+ include ::ActiveRecord
4
+
5
+ class << self
6
+ attr_accessor :app
7
+ end
8
+
9
+ def self.setup app
10
+ require 'mini_record'
11
+ self.app = app
12
+ ActiveRecord::Base.send :include, Form
13
+
14
+ if not Conjoin.env.mounted?
15
+ require 'enumerize'
16
+ require 'protector'
17
+ Protector::Adapters::ActiveRecord.activate!
18
+ start_active_record
19
+ else
20
+ ActiveRecord::Base.default_timezone = Time.zone
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def self.start_active_record
27
+ if not Conjoin.env.test?
28
+ return if ActiveRecord::Base.connected?
29
+ else
30
+ if ActiveRecord::Base.connected?
31
+ ActiveRecord::Base.connection.disconnect!
32
+ end
33
+ end
34
+ # ActiveRecord::Base.logger = Logger.new(STDERR) unless @app.test?
35
+
36
+ db = URI.parse ENV['DATABASE_URL']
37
+
38
+ ActiveRecord::Base.establish_connection(
39
+ adapter: db.scheme == 'postgres' ? 'postgresql' : db.scheme,
40
+ encoding: 'utf8',
41
+ reconnect: true,
42
+ database: db.path[1..-1],
43
+ host: db.host,
44
+ port: db.port,
45
+ pool: ENV['DATABASE_POOL'] || 5,
46
+ username: db.user,
47
+ password: db.password,
48
+ wait_timeout: 2147483
49
+ )
50
+ end
51
+
52
+ module Form
53
+ extend ActiveSupport::Concern
54
+
55
+ attr_accessor :req_params
56
+
57
+ included do
58
+ define_model_callbacks :validates, :save_as
59
+ before_save :save_unrestricted_attributes
60
+ end
61
+
62
+ def is_form?
63
+ self.class.model_name.to_s[/Form$/]
64
+ end
65
+
66
+ def validate
67
+ end
68
+
69
+ def validates req_params
70
+ req_params = req_params.is_a?(OpenStruct) ? req_params.to_hash : HashIndifferent.new(req_params)
71
+ @req_params = req_params
72
+
73
+ run_callbacks :validates do
74
+ self.attributes = req_params
75
+ valid?
76
+ end
77
+ end
78
+
79
+ def save_as current_user
80
+ run_callbacks :save_as do
81
+ add_creator_and_updater_for self, current_user, req_params
82
+ save!
83
+ end
84
+ end
85
+
86
+ def save_unrestricted_attributes
87
+ if @unrestricted_attributes and @unrestricted_attributes.any?
88
+ @unrestricted_attributes.each do |field, value|
89
+ self.send "#{field}=", value
90
+ end
91
+ end
92
+ end
93
+
94
+ def set_unrestricted_attribute field, value
95
+ @unrestricted_attributes ||= {}
96
+ @unrestricted_attributes[field] = value
97
+ end
98
+
99
+ def set_unrestricted_attributes *fields
100
+ fields.extract_options!.each do |field, value|
101
+ set_unrestricted_attribute field, value
102
+ end
103
+ end
104
+
105
+ def add_creator_and_updater_for(model, current_user = nil, current_params)
106
+ # set the creator and updater
107
+ id = current_user.try(:id) || ENV["SYSTEM_USER_ID"]
108
+
109
+ # Save creator
110
+ if model.respond_to? :creator_id and model.new_record?
111
+ model.set_unrestricted_attribute 'creator_id', id
112
+ end
113
+
114
+ # Save updater
115
+ if model.respond_to? :updater_id
116
+ model.set_unrestricted_attribute 'updater_id', id
117
+ end
118
+
119
+ return unless current_params
120
+ # loop through associated records
121
+ current_params.each do |name, value|
122
+ if name.end_with?("_attributes")
123
+ associated_name = name.gsub(/_attributes$/, '')
124
+ associated_model = model.try associated_name
125
+
126
+ if associated_model.kind_of? ::ActiveRecord::Base
127
+ new_current_params = current_params[name]
128
+ if new_current_params.kind_of? Hash
129
+ add_creator_and_updater_for associated_model, current_user, new_current_params
130
+ end
131
+ elsif associated_model.kind_of? ActiveRecord::Associations::CollectionProxy
132
+ new_current_params = current_params[name]
133
+ associated_model.each_with_index do |current_model, i|
134
+ add_creator_and_updater_for current_model, current_user, new_current_params[i]
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
140
+
141
+ def remove_error!(attribute, message = :invalid, options = {})
142
+ # -- Same code as private method ActiveModel::Errors.normalize_message(attribute, message, options).
143
+ callbacks_options = [:if, :unless, :on, :allow_nil, :allow_blank, :strict]
144
+ case message
145
+ when Symbol
146
+ message = self.errors.generate_message(attribute, message, options.except(*callbacks_options))
147
+ when Proc
148
+ message = message.call
149
+ else
150
+ message = message
151
+ end
152
+ # -- end block
153
+
154
+ # -- Delete message - based on ActiveModel::Errors.added?(attribute, message = :invalid, options = {}).
155
+ message = self.errors[attribute].delete(message) rescue nil
156
+ # -- Delete attribute from errors if message array is empty.
157
+ self.errors.messages.delete(attribute) if !self.errors.messages[attribute].present?
158
+ return message
159
+ end
160
+
161
+ def valid_except?(except={})
162
+ self.valid?
163
+ # -- Use this to call valid? for superclass if self.valid? is overridden.
164
+ # self.class.superclass.instance_method(:valid?).bind(self).call
165
+ except.each do |attribute, message|
166
+ if message.present?
167
+ remove_error!(attribute, message)
168
+ else
169
+ self.errors.delete(attribute)
170
+ end
171
+ end
172
+ !self.errors.present?
173
+ end
174
+
175
+ def valid_only? *columns
176
+ self.valid?
177
+ self.errors.messages.each do |field, message|
178
+ self.errors.delete(field) unless columns.include? field
179
+ end
180
+ !self.errors.present?
181
+ end
182
+ end
183
+ end
184
+ end
185
+
186
+ # https://github.com/rails/rails/blob/4-1-stable/activerecord/lib/active_record/associations/association_scope.rb#L63
187
+ # module ActiveRecord
188
+ # module Associations
189
+ # class AssociationScope #:nodoc:
190
+ # def add_constraints(scope, owner, assoc_klass, refl, tracker)
191
+ # chain = refl.chain
192
+ # scope_chain = refl.scope_chain
193
+ #
194
+ # tables = construct_tables(chain, assoc_klass, refl, tracker)
195
+ #
196
+ # chain.each_with_index do |reflection, i|
197
+ # table, foreign_table = tables.shift, tables.first
198
+ #
199
+ # if reflection.source_macro == :belongs_to
200
+ # if reflection.options[:polymorphic]
201
+ # key = reflection.association_primary_key(assoc_klass)
202
+ # else
203
+ # key = reflection.association_primary_key
204
+ # end
205
+ #
206
+ # foreign_key = reflection.foreign_key
207
+ # else
208
+ # key = reflection.foreign_key
209
+ # foreign_key = reflection.active_record_primary_key
210
+ # end
211
+ #
212
+ # if reflection == chain.last
213
+ # bind_val = bind scope, table.table_name, key.to_s, owner[foreign_key], tracker
214
+ # scope = scope.where(table[key].eq(bind_val))
215
+ #
216
+ # if reflection.type
217
+ # #############################################
218
+ # #############################################
219
+ # #############################################
220
+ # #############################################
221
+ # #############################################
222
+ # #############################################
223
+ # # .gsub(/\w+::/, '')
224
+ # # is a fix for polymorphic associations like
225
+ # # VendorWizard::VendorGroup so it can work
226
+ # # with the _type VendorGroup instead of
227
+ # # VendorWizard::VendorGroup
228
+ # #############################################
229
+ # #############################################
230
+ # #############################################
231
+ # #############################################
232
+ # #############################################
233
+ # value = owner.class.base_class.name.gsub(/\w+::/, '')
234
+ # #############################################
235
+ # bind_val = bind scope, table.table_name, reflection.type.to_s, value, tracker
236
+ # scope = scope.where(table[reflection.type].eq(bind_val))
237
+ # end
238
+ # else
239
+ # constraint = table[key].eq(foreign_table[foreign_key])
240
+ #
241
+ # if reflection.type
242
+ # value = chain[i + 1].klass.base_class.name
243
+ # bind_val = bind scope, table.table_name, reflection.type.to_s, value, tracker
244
+ # scope = scope.where(table[reflection.type].eq(bind_val))
245
+ # end
246
+ #
247
+ # scope = scope.joins(join(foreign_table, constraint))
248
+ # end
249
+ #
250
+ # is_first_chain = i == 0
251
+ # klass = is_first_chain ? assoc_klass : reflection.klass
252
+ #
253
+ # # Exclude the scope of the association itself, because that
254
+ # # was already merged in the #scope method.
255
+ # scope_chain[i].each do |scope_chain_item|
256
+ # item = eval_scope(klass, scope_chain_item, owner)
257
+ #
258
+ # if scope_chain_item == refl.scope
259
+ # scope.merge! item.except(:where, :includes, :bind)
260
+ # end
261
+ #
262
+ # if is_first_chain
263
+ # scope.includes! item.includes_values
264
+ # end
265
+ #
266
+ # scope.where_values += item.where_values
267
+ # scope.order_values |= item.order_values
268
+ # end
269
+ # end
270
+ #
271
+ # scope
272
+ # end
273
+ # end
274
+ # end
275
+ # end
276
+ # ACTIVERECORD 4.0.3
277
+ module ActiveRecord
278
+ module Associations
279
+ class AssociationScope #:nodoc:
280
+ def add_constraints(scope)
281
+ tables = construct_tables
282
+
283
+ chain.each_with_index do |reflection, i|
284
+ table, foreign_table = tables.shift, tables.first
285
+
286
+ if reflection.source_macro == :has_and_belongs_to_many
287
+ join_table = tables.shift
288
+
289
+ scope = scope.joins(join(
290
+ join_table,
291
+ table[reflection.association_primary_key].
292
+ eq(join_table[reflection.association_foreign_key])
293
+ ))
294
+
295
+ table, foreign_table = join_table, tables.first
296
+ end
297
+
298
+ if reflection.source_macro == :belongs_to
299
+ if reflection.options[:polymorphic]
300
+ key = reflection.association_primary_key(self.klass)
301
+ else
302
+ key = reflection.association_primary_key
303
+ end
304
+
305
+ foreign_key = reflection.foreign_key
306
+ else
307
+ key = reflection.foreign_key
308
+ foreign_key = reflection.active_record_primary_key
309
+ end
310
+
311
+ if reflection == chain.last
312
+ bind_val = bind scope, table.table_name, key.to_s, owner[foreign_key]
313
+ scope = scope.where(table[key].eq(bind_val))
314
+
315
+ if reflection.type
316
+ #############################################
317
+ #############################################
318
+ #############################################
319
+ #############################################
320
+ #############################################
321
+ #############################################
322
+ # .gsub(/\w+::/, '')
323
+ # is a fix for polymorphic associations like
324
+ # VendorWizard::VendorGroup so it can work
325
+ # with the _type VendorGroup instead of
326
+ # VendorWizard::VendorGroup
327
+ #############################################
328
+ #############################################
329
+ #############################################
330
+ #############################################
331
+ #############################################
332
+ value = owner.class.base_class.name.gsub(/\w+::/, '')
333
+ #############################################
334
+ bind_val = bind scope, table.table_name, reflection.type.to_s, value
335
+ scope = scope.where(table[reflection.type].eq(bind_val))
336
+ end
337
+
338
+ else
339
+ constraint = table[key].eq(foreign_table[foreign_key])
340
+
341
+ if reflection.type
342
+ type = chain[i + 1].klass.base_class.name
343
+ constraint = constraint.and(table[reflection.type].eq(type))
344
+ end
345
+
346
+ scope = scope.joins(join(foreign_table, constraint))
347
+ end
348
+
349
+ is_first_chain = i == 0
350
+ klass = is_first_chain ? self.klass : reflection.klass
351
+
352
+ # Exclude the scope of the association itself, because that
353
+ # was already merged in the #scope method.
354
+ scope_chain[i].each do |scope_chain_item|
355
+ item = eval_scope(klass, scope_chain_item)
356
+
357
+ if scope_chain_item == self.reflection.scope
358
+ scope.merge! item.except(:where, :includes)
359
+ end
360
+
361
+ if is_first_chain
362
+ scope.includes! item.includes_values
363
+ end
364
+
365
+ scope.where_values += item.where_values
366
+ scope.order_values |= item.order_values
367
+ end
368
+ end
369
+
370
+ scope
371
+ end
372
+ end
373
+ end
374
+ end
@@ -0,0 +1,205 @@
1
+ module Conjoin
2
+ module Assets
3
+ class << self
4
+ attr_accessor :app
5
+ end
6
+
7
+ def self.setup app
8
+ self.app = app
9
+
10
+ require 'mimemagic'
11
+ require 'base64'
12
+ require 'slim'
13
+ require 'sass'
14
+ require 'ostruct'
15
+
16
+ # if ENV['RACK_ENV'] != 'production'
17
+ # require 'rugged'
18
+ # end
19
+
20
+ Slim::Engine.set_default_options \
21
+ disable_escape: true,
22
+ use_html_safe: true,
23
+ disable_capture: false,
24
+ pretty: (Conjoin.env.production? or Conjoin.env.staging?) ? false : true
25
+
26
+ app.settings[:assets] ||= OpenStruct.new({
27
+ settings: {},
28
+ stylesheet: [],
29
+ images: [],
30
+ javascript_head: [],
31
+ javascript: []
32
+ })
33
+ end
34
+
35
+ %w(stylesheet javascript javascript_head).each do |type|
36
+ define_method "#{type}_assets" do
37
+ plugin[:"#{type}"]
38
+ end
39
+ end
40
+
41
+ def asset_path file
42
+ case file[/(\.[^.]+)$/]
43
+ when '.css', '.js'
44
+ path = "#{plugin.settings[:path] || '/'}#{cache_string}assets/#{file}"
45
+ else
46
+ path = "#{plugin.settings[:path] || '/'}#{cache_string}assets/images/#{file}"
47
+ end
48
+ "http#{req.env['SERVER_PORT'] == '443' ? 's' : ''}://#{req.env['HTTP_HOST']}#{path}"
49
+ end
50
+
51
+ def image_tag file, options = {}
52
+ options[:src] = asset_path(file)
53
+ mab do
54
+ img options
55
+ end
56
+ end
57
+
58
+ def fa_icon icon, options = {}
59
+ options[:class] ||= ''
60
+ options[:class] += " fa fa-#{icon}"
61
+
62
+ mab do
63
+ i options
64
+ end
65
+ end
66
+
67
+ def accepted_assets
68
+ "(.*)\.(js|css|eot|svg|ttf|woff|png|gif|jpg|jpeg)$"
69
+ end
70
+
71
+ private
72
+
73
+ def cache_string
74
+ if Conjoin.env.mounted?
75
+ # @cache_string ||= (File.read "#{Assets.app.root}/sha") + "/"
76
+ "/"
77
+ end
78
+ end
79
+
80
+ def plugin
81
+ Assets.app.settings[:assets]
82
+ end
83
+
84
+ def links_for type, opts = {}
85
+ method = :link
86
+ path = :href
87
+ extention = :css
88
+
89
+ options = {
90
+ 'data-turbolinks-track' => true
91
+ }
92
+
93
+ case type
94
+ when :stylesheet_assets
95
+ options.merge!({
96
+ rel: 'stylesheet',
97
+ type: 'text/css',
98
+ media: 'all'
99
+ })
100
+ when :javascript_assets, :javascript_head_assets
101
+ method = :script
102
+ path = :src
103
+ extention = :js
104
+ else
105
+ raise 'Please choose a type: stylesheet_assets, javascript_head_assets or javascript_assets'
106
+ end
107
+
108
+ # merge in the user options allowing them to override
109
+ options.merge! opts
110
+
111
+ app = self
112
+
113
+ mab do
114
+ if Conjoin.env.production? or Conjoin.env.staging?
115
+ options[path] = asset_path "#{type}.#{extention}"
116
+ send(method, options)
117
+ else
118
+ app.send(type).each do |asset|
119
+ options[path] = asset_path asset.gsub(/\.coffee/, '.js').gsub(/\.scss/, '.css')
120
+ send(method, options)
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+ module ClassMethods
127
+ %w(stylesheet javascript javascript_head).each do |type|
128
+ define_method "#{type}_assets" do |files|
129
+ files.each do |path|
130
+ settings[:assets][:"#{type}"] << path
131
+ end
132
+ end
133
+ end
134
+
135
+ def all_assets
136
+ settings[:assets]
137
+ end
138
+
139
+ def assets_settings as
140
+ settings[:assets].settings.merge! as
141
+ end
142
+ end
143
+
144
+ class Helpers
145
+ def asset_path path
146
+ app.root + '/app/assets/' + path
147
+ end
148
+ end
149
+
150
+ class Routes < Struct.new(:settings)
151
+ def app
152
+ App.settings = settings
153
+ App.root = Conjoin::Assets.app.root
154
+ App.plugin Conjoin::Cuba::Render
155
+ App.plugin Assets
156
+ App
157
+ end
158
+ end
159
+
160
+ # erb = Tilt::ERBTemplate.new "#{Assets.app.root}/app/assets/#{file}.scss"
161
+ # scss = Tilt::ScssTemplate.new{ erb.render(Helpers.new) }
162
+
163
+ # scss.render
164
+ class App < Conjoin::Cuba
165
+ def add_asset file, ext
166
+ dir = ''
167
+ new_ext = false
168
+
169
+ case ext
170
+ when 'css'
171
+ dir = !file[/^bower/] ? 'stylesheets/' : ''
172
+ new_ext = 'scss' if stylesheet_assets.include? file + '.scss'
173
+ when 'js'
174
+ dir = !file[/^bower/] ? 'javascripts/' : ''
175
+ new_ext = 'coffee' if javascript_assets.include? file + '.coffee' \
176
+ or javascript_head_assets.include? file + '.coffee'
177
+ end
178
+
179
+ if new_ext
180
+ render "#{Assets.app.root}/app/assets/#{dir}#{file}.#{new_ext}"
181
+ else
182
+ File.read "#{Assets.app.root}/app/assets/#{dir}#{file}.#{ext}"
183
+ end
184
+ end
185
+
186
+ define do
187
+ on get, accepted_assets do |file, ext|
188
+ res.headers["Content-Type"] = "#{MimeMagic.by_extension(ext).to_s}; charset=utf-8"
189
+
190
+ if %w(stylesheet_assets javascript_head_assets javascript_assets).include? file
191
+ content = ''
192
+
193
+ send(file).each do |asset|
194
+ content += add_asset asset.sub(/(\.)(?!.*\.).+/, ""), ext
195
+ end
196
+
197
+ res.write content
198
+ else
199
+ res.write add_asset file, ext
200
+ end
201
+ end
202
+ end
203
+ end
204
+ end
205
+ end