conjoin 0.0.1 → 0.0.2

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 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