lux-fw 0.2.3 → 0.5.32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. checksums.yaml +4 -4
  2. data/.version +1 -1
  3. data/bin/README.md +33 -0
  4. data/bin/build_gem +76 -0
  5. data/bin/cli/config.rb +44 -0
  6. data/bin/cli/console.rb +61 -0
  7. data/bin/cli/dbconsole.rb +8 -0
  8. data/bin/cli/eval.rb +32 -0
  9. data/bin/cli/generate.rb +88 -0
  10. data/bin/cli/get.rb +12 -0
  11. data/bin/cli/new.rb +22 -0
  12. data/bin/cli/routes.rb +90 -0
  13. data/bin/cli/secrets.rb +40 -0
  14. data/bin/cli/server.rb +24 -0
  15. data/bin/cli/stats.rb +133 -0
  16. data/bin/lux +24 -65
  17. data/lib/common/class_attributes.rb +40 -64
  18. data/lib/common/class_callbacks.rb +34 -51
  19. data/lib/common/crypt.rb +10 -8
  20. data/lib/common/free_struct.rb +42 -0
  21. data/lib/common/hash_with_indifferent_access.rb +1 -1
  22. data/lib/common/html_tag_builder.rb +26 -2
  23. data/lib/common/url.rb +58 -40
  24. data/lib/lux/application/application.rb +290 -117
  25. data/lib/lux/application/lib/nav.rb +64 -38
  26. data/lib/lux/application/lib/render.rb +2 -1
  27. data/lib/lux/cache/cache.rb +87 -62
  28. data/lib/lux/cache/lib/{ram.rb → memory.rb} +5 -7
  29. data/lib/lux/cache/lib/null.rb +6 -8
  30. data/lib/lux/config/config.rb +109 -52
  31. data/lib/lux/config/lib/plugin.rb +65 -0
  32. data/lib/lux/config/lib/secrets.rb +48 -0
  33. data/lib/lux/controller/controller.rb +241 -0
  34. data/lib/lux/current/current.rb +33 -47
  35. data/lib/lux/current/lib/session.rb +72 -0
  36. data/lib/lux/delayed_job/delayed_job.rb +14 -7
  37. data/lib/lux/delayed_job/lib/memory.rb +7 -5
  38. data/lib/lux/delayed_job/lib/redis.rb +1 -1
  39. data/lib/lux/error/error.rb +164 -62
  40. data/lib/lux/event_bus/event_bus.rb +27 -0
  41. data/lib/lux/lux.rb +103 -66
  42. data/lib/lux/mailer/mailer.rb +23 -25
  43. data/lib/lux/response/lib/file.rb +81 -0
  44. data/lib/lux/response/lib/header.rb +14 -1
  45. data/lib/lux/response/response.rb +64 -56
  46. data/lib/lux/view/cell.rb +102 -0
  47. data/lib/lux/{helper → view}/helper.rb +39 -23
  48. data/lib/lux/view/lib/cell_helpers.rb +29 -0
  49. data/lib/lux/{helper/helpers/mailer_helper.rb → view/lib/helper_modules.rb} +7 -1
  50. data/lib/lux/{template/template.rb → view/view.rb} +21 -24
  51. data/lib/lux-fw.rb +4 -2
  52. data/lib/overload/array.rb +12 -6
  53. data/lib/overload/blank.rb +0 -1
  54. data/lib/overload/dir.rb +18 -0
  55. data/lib/overload/file.rb +1 -6
  56. data/lib/overload/hash.rb +56 -13
  57. data/lib/overload/integer.rb +2 -2
  58. data/lib/overload/it.rb +4 -4
  59. data/lib/overload/object.rb +37 -8
  60. data/lib/overload/{r.rb → raise_variants.rb} +23 -4
  61. data/lib/overload/string.rb +22 -6
  62. data/misc/demo/app/cells/demo_cell.rb +12 -0
  63. data/misc/demo/app/controllers/application_controller.rb +7 -0
  64. data/misc/demo/app/controllers/main/root_controller.rb +9 -0
  65. data/misc/demo/app/routes.rb +5 -0
  66. data/misc/demo/config/application.rb +14 -0
  67. data/misc/demo/config/assets.rb +6 -0
  68. data/misc/demo/config/environment.rb +7 -0
  69. data/misc/puma_auto_tune.rb +43 -0
  70. data/misc/unicorn.rb +37 -0
  71. data/{lib/lux → plugins}/api/api.rb +46 -29
  72. data/plugins/api/lib/attr.rb +31 -0
  73. data/{lib/lux → plugins}/api/lib/dsl.rb +3 -6
  74. data/{lib/lux → plugins}/api/lib/error.rb +0 -0
  75. data/{lib/lux → plugins}/api/lib/model_api.rb +51 -12
  76. data/{lib/lux → plugins}/api/lib/response.rb +31 -17
  77. data/{bin/cli/am → plugins/db/auto_migrate/auto_migrate.rb} +18 -35
  78. data/plugins/db/helpers/array_search.rb +27 -0
  79. data/plugins/db/helpers/before_save_filters.rb +32 -0
  80. data/plugins/db/helpers/composite_primary_keys.rb +36 -0
  81. data/plugins/db/helpers/core.rb +94 -0
  82. data/plugins/db/helpers/dataset_methods.rb +138 -0
  83. data/plugins/db/helpers/enums_plugin.rb +52 -0
  84. data/plugins/db/helpers/find_precache.rb +31 -0
  85. data/plugins/db/helpers/link_objects.rb +84 -0
  86. data/plugins/db/helpers/schema_checks.rb +83 -0
  87. data/plugins/db/helpers/typero_adapter.rb +71 -0
  88. data/plugins/db/logger/config.rb +22 -0
  89. data/plugins/db/logger/lux_response_adapter.rb +10 -0
  90. data/plugins/db/paginate/helper.rb +32 -0
  91. data/plugins/db/paginate/sequel_adapter.rb +23 -0
  92. data/plugins/exceptions/simple_exception.rb +64 -0
  93. data/plugins/favicon/favicon.rb +10 -0
  94. data/plugins/html/html_form.rb +118 -0
  95. data/plugins/html/html_input.rb +98 -0
  96. data/plugins/html/html_menu.rb +79 -0
  97. data/plugins/html/input_types.rb +346 -0
  98. data/plugins/js_widgets/js_widgets.rb +15 -0
  99. data/plugins/oauth/lib/facebook.rb +35 -0
  100. data/plugins/oauth/lib/github.rb +38 -0
  101. data/plugins/oauth/lib/google.rb +41 -0
  102. data/plugins/oauth/lib/linkedin.rb +41 -0
  103. data/plugins/oauth/lib/stackexchange.rb +41 -0
  104. data/plugins/oauth/lib/twitter.rb +38 -0
  105. data/plugins/oauth/oauth.rb +42 -0
  106. data/{lib/common → plugins/policy}/policy.rb +6 -7
  107. data/tasks/loader.rb +49 -0
  108. metadata +151 -49
  109. data/bin/cli/assets +0 -41
  110. data/bin/cli/console +0 -51
  111. data/bin/cli/dev +0 -1
  112. data/bin/cli/eval +0 -24
  113. data/bin/cli/exceptions +0 -62
  114. data/bin/cli/generate +0 -86
  115. data/bin/cli/get +0 -5
  116. data/bin/cli/nginx +0 -34
  117. data/bin/cli/production +0 -1
  118. data/bin/cli/render +0 -18
  119. data/bin/cli/routes +0 -14
  120. data/bin/cli/server +0 -4
  121. data/bin/cli/stat +0 -1
  122. data/bin/cli/systemd +0 -36
  123. data/bin/txt/nginx.conf +0 -46
  124. data/bin/txt/siege-and-puma.txt +0 -3
  125. data/lib/common/base32.rb +0 -47
  126. data/lib/common/dynamic_class.rb +0 -28
  127. data/lib/common/folder_model.rb +0 -50
  128. data/lib/common/generic_model.rb +0 -62
  129. data/lib/lux/application/lib/plugs.rb +0 -10
  130. data/lib/lux/application/lib/route_test.rb +0 -64
  131. data/lib/lux/cache/lib/memcached.rb +0 -3
  132. data/lib/lux/cell/cell.rb +0 -261
  133. data/lib/lux/current/lib/static_file.rb +0 -103
  134. data/lib/lux/helper/helpers/application_helper.rb +0 -3
  135. data/lib/lux/helper/helpers/html_helper.rb +0 -3
  136. data/lib/overload/auto_loader.rb +0 -27
  137. data/lib/overload/module.rb +0 -10
  138. data/lib/overload/string_inflections.rb +0 -8
data/bin/lux CHANGED
@@ -1,16 +1,26 @@
1
1
  #!/usr/bin/env ruby
2
+ # -*- mode: ruby -*-
2
3
 
3
4
  if File.exists?('lux-fw.gemspec')
4
5
  puts 'Cant run in lux folder'
5
6
  exit
6
7
  end
7
8
 
9
+ require 'thor'
8
10
  require 'colorize'
9
11
  require 'optparse'
10
12
  require 'awesome_print'
11
13
  require 'dotenv'
12
14
 
13
- module LuxCli
15
+ Dotenv.load
16
+
17
+ LUX_ROOT = File.expand_path '../..', __FILE__
18
+
19
+ puts 'Lux (%s, v%s)' % [LUX_ROOT, File.read('%s/.version' % LUX_ROOT)] unless ARGV[0]
20
+
21
+ ###
22
+
23
+ module Cli
14
24
  extend self
15
25
 
16
26
  def run what
@@ -22,76 +32,25 @@ module LuxCli
22
32
  puts text.red
23
33
  exit
24
34
  end
35
+
36
+ def info text
37
+ puts '* %s' % text.magenta
38
+ end
25
39
  end
26
40
 
27
- Dotenv.load
41
+ ###
28
42
 
29
- @port = 3000
30
- lux_root = File.expand_path '../..', __FILE__
43
+ trap("SIGINT") { Cli.die 'ctrl+c exit' }
31
44
 
32
- if Dir.exists?('.git')
33
- test_root = `bundle show lux-fw`.chomp
34
- lux_root = test_root if test_root.include?('lux')
35
- end
45
+ LuxCli = Class.new Thor
36
46
 
37
- puts 'Lux (%s, v%s)' % [lux_root, File.read('%s/.version' % lux_root)] unless ARGV[0]
47
+ Dir['%s/bin/cli/*.rb' % LUX_ROOT].each { |it| load it }
38
48
 
39
- ARGV.options do |opts|
40
- opts.on("-e", "--environment=val", "RACK_ENV enviroment", String) do |v|
41
- v = 'production' if v[0,1] == 'p'
42
- v = 'development' if v[0,1] == 'd'
43
- ENV['RACK_ENV'] = v if v
44
- end
45
- opts.on("-p", "--port=val", "port (3000)", String) do |v|
46
- @port = v.to_i
47
- end
48
- opts.on("-f", "--flags=val", "CRSL", String) do |v|
49
- @flags = v
50
- end
51
- end.parse!
52
-
53
- commands = {}
54
- commands['am'] = 'auto migrate'
55
- commands['assets'] = 'precompile assets and genereate mainifest.json'
56
- commands['console'] = 'Lux console'
57
- commands['dev'] = 'dev on port 3000 with hot reload on code change'
58
- commands['eval'] = 'eval code or file'
59
- commands['exceptions'] = 'show stored exceptions, last created first'
60
- commands['generate'] = 'generates models and views based on templates'
61
- commands['get'] = 'get local URL'
62
- commands['nginx'] = 'parse and install config/nginx.conf'
63
- commands['production'] = 'run puma in production mode'
64
- commands['routes'] = 'list routes'
65
- commands['render'] = 'render single page'
66
- commands['server'] = 'run puma development server'
67
- commands['systemd'] = 'parse and install config/systemd.conf'
68
- commands['stat'] = 'goaccess stat to public/goaccess.html'
69
- # commands['job_que'] = 'process job que with loaded enviroment'
70
-
71
- command = ARGV.shift
72
-
73
- if command
74
- for c in commands
75
- command = c[0] if c[0] if c[0].start_with?(command)
76
- end
49
+ LuxCli.start ARGV
77
50
 
78
- if commands[command]
79
- path = '%s/bin/cli/%s' % [lux_root, command]
80
- load path
81
- else
82
- LuxCli.die "Can't find command [%s]" % command
83
- end
84
- else
85
- puts "\nCommands:"
86
- for c in commands
87
- # puts " #{c[0].sub(/(\w)/,'[\\1]').ljust(15)} # #{c[1]}"
88
- puts " #{c[0].ljust(15)} # #{c[1]}"
89
- end
51
+ rakes = Dir['./Rakefile*'] + Dir['./rakefile*']
90
52
 
91
- puts "\nExamples:"
92
- puts ' lux c # lux console'
93
- puts ' lux g user # lux generate user users'
94
- puts ''
95
- exit
53
+ if !ARGV[0] && rakes[0]
54
+ puts 'Or use one of rake tasks'
55
+ puts ' ' + `rake -T`.gsub($/, "\n ")
96
56
  end
97
-
@@ -1,75 +1,51 @@
1
- # frozen_string_literal: true
1
+ # Defines class variable
2
2
 
3
- # ClassAttributes.define klass, :layout, 'default_value_optional'
4
- # klass.layout -> get value
5
- # klass.layout = value -> set value
3
+ def Object.class_attribute name, default=nil, &block
4
+ raise ArgumentError.new('name must be symbol') unless name.is_a?(Symbol)
5
+
6
+ ivar = "@cattr_#{name}"
7
+ instance_variable_set ivar, block || default
8
+
9
+ define_singleton_method('%s=' % name) { |arg| send(name, arg) }
10
+ define_singleton_method(name) do |arg=:_undefined|
11
+ # define and set if argument given
12
+ if arg != :_undefined
13
+ instance_variable_set ivar, arg
14
+ return arg
15
+ end
16
+
17
+ # find value and return
18
+ ancestors.each do |klass|
19
+ if klass.instance_variable_defined?(ivar)
20
+ value = klass.instance_variable_get ivar
21
+ return value.is_a?(Proc) ? instance_exec(&value) : value
22
+ end
23
+ end
24
+ end
25
+ end
6
26
 
7
27
  # class A
8
- # ClassAttributes.define self, :layout, 'default'
28
+ # class_attribute :layout, 'default'
29
+ # class_attribute(:time) { Time.now }
9
30
  # end
31
+
10
32
  # class B < A
11
- # layout 'l B'
33
+ # layout 'main'
12
34
  # end
35
+
13
36
  # class C < B
37
+ # time '11:55'
14
38
  # end
15
- # puts A.layout # default
16
- # puts B.layout # l B
17
- # puts C.layout # l B
18
39
 
19
- # class User
20
- # ClassAttributes.define_in_current_thread self, :current
40
+ # for func in [:layout, :time]
41
+ # for klass in [A, B, C]
42
+ # puts "> %s = %s" % ["#{klass}.#{func}".ljust(8), klass.send(func)]
43
+ # end
21
44
  # end
22
45
 
23
- # User.current = User.first
24
-
25
- module ClassAttributes
26
- extend self
27
-
28
- CA_DEFAULTS = {}
29
-
30
- # defines class variable
31
- def define klass, name, default=nil, &block
32
- raise ArgumentError, 'name must be symbol' unless name.class == Symbol
33
-
34
- default ||= block if block
35
-
36
- ::ClassAttributes::CA_DEFAULTS[name] = { 'Object'=>default }
37
-
38
- klass.define_singleton_method('%s=' % name) { |*args| send name, *args}
39
- klass.define_singleton_method(name) do |*args|
40
- root = ::ClassAttributes::CA_DEFAULTS[name]
41
-
42
- # set and return if argument defined
43
- return root[to_s] = args[0] if args.length > 0
44
-
45
- # find value and return
46
- ancestors.map(&:to_s).each do |el|
47
- value = root[el]
48
- if value || el == 'Object'
49
- value = instance_exec(&value) if value.is_a?(Proc)
50
- return value
51
- end
52
- end
53
- end
54
- end
55
-
56
- # defines class variable in current lux thread
57
- # User.current = @user
58
- # def current klass, name
59
- # klass.class.send(:define_method, name) do |*args|
60
- # Thread.current[:lux] ||= {}
61
- # Thread.current[:lux]['%s-%s' % [klass, name]]
62
- # end
63
-
64
- # klass.class.send(:define_method, '%s=' % name) do |value|
65
- # Thread.current[:lux] ||= {}
66
- # Thread.current[:lux]['%s-%s' % [klass, name]] = value
67
- # end
68
- # end
69
- end
70
-
71
- class Object
72
- def class_attribute name, default=nil, &block
73
- ClassAttributes.define self, name, default, &block
74
- end
75
- end
46
+ # # > A.layout = default
47
+ # # > B.layout = main
48
+ # # > C.layout = main
49
+ # # > A.time = 2018-10-28 18:07:33 +0100
50
+ # # > B.time = 2018-10-28 18:07:33 +0100
51
+ # # > C.time = 11:55
@@ -1,64 +1,47 @@
1
- # frozen_string_literal: true
1
+ # Rails style callbacks
2
2
 
3
- # in some class
4
- # ClassCallbacks.define self, :before, :after
5
- #
6
- # then to execute
7
- # instance_object = SomeClass.new
8
- # ClassCallbacks.execute(instance_object, :before)
9
- #
3
+ # for controllers, execute from AppController to MainController
4
+ # class_callback :before
10
5
  # before do
11
- # ...
6
+ # ...
12
7
  # end
13
- #
14
- # logic is very simple, keep all pointers to all blocks in one class, resolve and execute as needed
15
- # we keep methods and ponters in different hashes to allow hot reload while development
16
-
17
- module ClassCallbacks
18
- extend self
19
-
20
- @@methods = {}
21
- @@pointers = {}
22
-
23
- def add klass, unique_id, action, method
24
- klass = klass.to_s
25
- key = Crypt.sha1(unique_id)
26
-
27
- @@pointers[key] = method
28
-
29
- @@methods[klass] ||= {}
30
- @@methods[klass][action] ||= []
31
- @@methods[klass][action].tap { |it| it.push(key) unless it.include?(key) }
8
+ # before :method_name
9
+ # instance = new
10
+ # instance.class_callback :before,
11
+ # instance.class_callback :before, arg
12
+
13
+ class Object
14
+ def class_callback name, arg=nil
15
+ Object.class_callback name, self, arg
32
16
  end
33
17
 
34
- def execute instance_object, action, object=nil
35
- object ? instance_object.send(action, object) : instance_object.send(action)
18
+ def self.class_callback name, context=nil, arg=nil
19
+ ivar = "@ccallbacks_#{name}"
36
20
 
37
- # execute for self and parents
38
- instance_object.class.ancestors.reverse.map(&:to_s).each do |name|
39
- next if name == 'Object'
40
- next unless actions = @@methods.dig(name, action)
21
+ unless context
22
+ define_singleton_method(name) do |method_name=nil, &block|
23
+ ref = caller[0].split(':in ').first
41
24
 
42
- for el in actions.map { |o| @@pointers[o] }
43
- if el.kind_of?(Symbol)
44
- object ? instance_object.send(el, object) : instance_object.send(el)
45
- else
46
- object ? instance_object.instance_exec(object, &el) : instance_object.instance_exec(&el)
47
- end
25
+ self.instance_variable_set(ivar, {}) unless instance_variable_defined?(ivar)
26
+ self.instance_variable_get(ivar)[ref] = method_name || block
48
27
  end
49
- end
50
- end
51
28
 
52
- def define(klass, *args)
53
- args.each do |action|
54
- klass.class_eval %[
55
- def #{action}(duck=nil)
29
+ else
30
+ list = context.respond_to?(:const_missing) ? context.ancestors : context.class.ancestors
31
+ list = list.slice 0, list.index(Object) if list.index(Object)
32
+
33
+ list.reverse.each do |klass|
34
+ if klass.instance_variable_defined?(ivar)
35
+ mlist = klass.instance_variable_get(ivar).values
36
+ mlist.each do |m|
37
+ if m.is_a?(Symbol)
38
+ context.send m
39
+ else
40
+ context.instance_exec arg, &m
41
+ end
42
+ end
56
43
  end
57
-
58
- def self.#{action}(proc=nil, &block)
59
- ClassCallbacks.add(self, caller[0], :#{action}, proc || block)
60
- end
61
- ]
44
+ end
62
45
  end
63
46
  end
64
47
  end
data/lib/common/crypt.rb CHANGED
@@ -15,7 +15,7 @@ module Crypt
15
15
  ALGORITHM = 'HS512'
16
16
 
17
17
  def secret
18
- ENV.fetch('SECRET') { puts '* Warn: ENV SECRET not set'; 'foo' }
18
+ ENV.fetch('SECRET') { Lux.config.secret } || die('Lux.config.secret not set')
19
19
  end
20
20
 
21
21
  def base64 str
@@ -44,22 +44,24 @@ module Crypt
44
44
 
45
45
  # Crypt.encrypt('secret')
46
46
  # Crypt.encrypt('secret', ttl:1.hour, password:'pa$$w0rd')
47
- def encrypt(data, opts={})
48
- opts = opts.to_opts!(:ttl, :password)
47
+ def encrypt data, opts={}
48
+ opts = opts.to_opts(:ttl, :password)
49
+ payload = { data:data }
50
+ payload[:ttl] = Time.now.to_i + opts.ttl.to_i if opts.ttl
49
51
 
50
- payload = { data:data }
51
- payload[:ttl] = Time.now.to_i + opts.ttl if opts.ttl
52
52
  JWT.encode payload, secret+opts.password.to_s, ALGORITHM
53
53
  end
54
54
 
55
55
  # Crypt.decrypt('secret')
56
56
  # Crypt.decrypt('secret', password:'pa$$w0rd')
57
- def decrypt(token, opts={})
58
- opts = opts.to_opts!(:password)
57
+ def decrypt token, opts={}
58
+ opts = opts.to_opts(:password, :ttl)
59
59
 
60
60
  token_data = JWT.decode token, secret+opts.password.to_s, true, { :algorithm => ALGORITHM }
61
61
  data = token_data[0]
62
- raise "Crypted data expired before #{Time.now.to_i - data.ttl} seconds" if data['ttl'] && data['ttl'] < Time.now.to_i
62
+
63
+ raise "Crypted data expired before #{Time.now.to_i - data['ttl']} seconds" if data['ttl'] && data['ttl'] < Time.now.to_i
64
+
63
65
  data['data']
64
66
  end
65
67
 
@@ -0,0 +1,42 @@
1
+ # Convert hash to object with methods
2
+ # o = FreeStruct.new name: 'a'
3
+ # o.name -> 'a'
4
+ # o[:name] -> 'a'
5
+ # o.name = 'b'
6
+ # o.name 'b'
7
+ # o.name -> 'b'
8
+ # o.name = nil
9
+ # o.name -> nil
10
+ # o.title -> raises error
11
+
12
+ class FreeStruct
13
+ def initialize hash
14
+ @keys = hash.keys
15
+
16
+ hash.each do |key, value|
17
+ ivar = "@#{key}"
18
+
19
+ instance_variable_set ivar, value
20
+
21
+ define_singleton_method(key) do
22
+ instance_variable_get ivar
23
+ end
24
+
25
+ define_singleton_method "#{key}=" do |val|
26
+ instance_variable_set ivar, val
27
+ end
28
+ end
29
+ end
30
+
31
+ def [] key
32
+ send key
33
+ end
34
+
35
+ def to_h
36
+ @keys.inject({}) do |out, key|
37
+ out[key] = send(key)
38
+ out
39
+ end
40
+ end
41
+ end
42
+
@@ -44,7 +44,7 @@ class HashWithIndifferentAccess
44
44
  end
45
45
 
46
46
  def dig *args
47
- list = args.map{ |it| it.class == Symbol ? it.to_s : it }
47
+ list = args.map{ |it| it.is_a?(Symbol) ? it.to_s : it }
48
48
  @data.dig *list
49
49
  end
50
50
 
@@ -3,6 +3,7 @@
3
3
  # n.li do |n|
4
4
  # n.i '.arrow'
5
5
  # n.span num
6
+ # n.id
6
7
  # end
7
8
  # end
8
9
  # end
@@ -17,8 +18,15 @@ class HtmlTagBuilder
17
18
  # tag :div, { 'class'=>'iform' } do
18
19
  def tag name=nil, opts={}, data=nil
19
20
  # covert tag.a '.foo.bar' to class names
20
- if opts.class == String && opts[0,1] == '.'
21
- opts = { class: opts.sub('.', '').gsub('.', ' ') }
21
+ # covert tag.a '#id' to id names
22
+ if opts.is_a?(String)
23
+ case opts[0,1]
24
+ when '.'
25
+ opts = { class: opts.sub('.', '').gsub('.', ' ') }
26
+ when '#'
27
+ opts = { id: opts.sub('#', '') }
28
+ end
29
+ else
22
30
  end
23
31
 
24
32
  # fix data and opts unless opts is Hash
@@ -50,6 +58,12 @@ class HtmlTagBuilder
50
58
  text ||= '' unless ['input', 'img', 'meta', 'link', 'hr', 'br'].include?(node.to_s)
51
59
  text ? %{<#{node}#{opts}>#{text}</#{node}>} : %{<#{node}#{opts} />}
52
60
  end
61
+
62
+ # tag.div(class: 'klasa') do -> tag.('klasa') do
63
+ def call class_name, &block
64
+ tag(:div, { class: class_name }, &block)
65
+ end
66
+
53
67
  end
54
68
 
55
69
  ###
@@ -60,6 +74,16 @@ class HtmlTagBuilder
60
74
  @data = []
61
75
  end
62
76
 
77
+ # push data to stack
78
+ def push data
79
+ @data.push data
80
+ end
81
+
82
+ # n.div(class: 'klasa') do -> n.('klasa') do
83
+ def call class_name, &block
84
+ @data.push self.class.tag(:div, { class: class_name }, &block)
85
+ end
86
+
63
87
  # forward to class
64
88
  def method_missing tag_name, *args, &block
65
89
  @data.push self.class.tag(tag_name, args[0], args[1], &block)
data/lib/common/url.rb CHANGED
@@ -30,14 +30,14 @@ class Url
30
30
  b.url
31
31
  end
32
32
 
33
- def qs name, value=nil
33
+ def qs name, value
34
34
  current.qs(name, value).relative
35
35
  end
36
36
 
37
37
  # for search
38
38
  # Url.prepare_qs(:q) -> /foo?bar=1&q=
39
39
  def prepare_qs name
40
- url = current.qs(name).relative
40
+ url = current.delete(name).relative
41
41
  url += url.index('?') ? '&' : '?'
42
42
  "#{url}#{name}="
43
43
  end
@@ -54,26 +54,28 @@ class Url
54
54
  ###
55
55
 
56
56
  def initialize url
57
- if url =~ /:/
58
- @elms = url.split '/', 4
59
- else
60
- @elms = [url]
61
- @elms.unshift '',''
57
+ url, qs_part = url.split('?', 2)
58
+
59
+ @qs = qs_part.to_s.split('&').inject({}) do |qs, el|
60
+ parts = el.split('=', 2)
61
+ qs[parts[0]] = Url.unescape parts[1]
62
+ qs
62
63
  end
63
64
 
64
- domain_and_port = @elms[2].split(':')
65
- @domain_parts = domain_and_port[0].to_s.split('.').reverse.map(&:downcase)
65
+ if url =~ %r{://}
66
+ @proto, _, @domain, @path = url.split '/', 4
67
+
68
+ @proto = @proto.sub(':', '')
66
69
 
67
- @qs = {}
68
- path_with_qs = @elms[3].to_s.split(/\?|#/)
69
- path_with_qs[1].split('&').map do |el|
70
- parts = el.split('=')
71
- @qs[parts[0]] = Url.unescape parts[1]
72
- end if path_with_qs[1]
70
+ @domain, @port = @domain.split(':', 2)
71
+ @port = nil if @port == '80' || @port.blank?
72
+
73
+ @domain_parts = @domain.split('.').reverse.map(&:downcase)
74
+ else
75
+ @path = url.to_s.sub(%r{^/}, '')
76
+ end
73
77
 
74
- @path = path_with_qs[0] || '/'
75
- @proto = @elms[0].split(':').first.downcase
76
- @port = domain_and_port[1] ? domain_and_port[1].to_i : 80
78
+ @path = '' if @path.blank?
77
79
  end
78
80
 
79
81
  def domain what=nil
@@ -85,11 +87,12 @@ class Url
85
87
  @domain_parts.slice(0,2).reverse.join '.'
86
88
  end
87
89
 
88
- def subdomain name
90
+ def subdomain name=nil
89
91
  if name
90
92
  @domain_parts[2] = name
91
93
  return self
92
94
  end
95
+
93
96
  @domain_parts.drop(2).reverse.join('.').or nil
94
97
  end
95
98
 
@@ -101,19 +104,17 @@ class Url
101
104
  @domain_parts.reverse.join '.'
102
105
  end
103
106
 
104
- def host_with_port
105
- %[#{proto}://#{host}#{port == 80 ? '' : ":#{port}"}]
106
- end
107
-
108
107
  def query
109
108
  @query
110
109
  end
111
110
 
112
111
  def path val=nil
113
- return '/'+@path+(@namespace ? ":#{@namespace}" : '') unless val
114
-
115
- @path = val.sub(/^\//,'')
116
- self
112
+ if val
113
+ @path = val.sub /^\//, ''
114
+ return self
115
+ else
116
+ '/' + @path
117
+ end
117
118
  end
118
119
 
119
120
  def delete *keys
@@ -125,13 +126,13 @@ class Url
125
126
  @hash = "##{val}"
126
127
  end
127
128
 
128
- def qs name, value=nil
129
- if value
129
+ def qs name, value=:_nil
130
+ if value != :_nil
130
131
  @qs[name.to_s] = value
132
+ self
131
133
  elsif name
132
- @qs.delete(name.to_s)
134
+ @qs[name.to_s]
133
135
  end
134
- self
135
136
  end
136
137
 
137
138
  def namespace data
@@ -141,21 +142,16 @@ class Url
141
142
 
142
143
  def locale what
143
144
  elms = @path.split('/')
145
+
144
146
  if elms[0] && Locale.all.index(elms[0].to_s)
145
147
  elms[0] = what
146
148
  else
147
149
  elms.unshift what
148
150
  end
151
+
149
152
  @path = elms.join('/')
150
- self
151
- end
152
153
 
153
- def qs_val
154
- ret = []
155
- if @qs.keys.length > 0
156
- ret.push '?' + @qs.keys.sort.map{ |key| "#{key}=#{Url.escape(@qs[key].to_s)}" }.join('&')
157
- end
158
- ret.join('')
154
+ self
159
155
  end
160
156
 
161
157
  def url
@@ -167,7 +163,29 @@ class Url
167
163
  end
168
164
 
169
165
  def to_s
170
- domain.length > 0 ? url : local_url
166
+ @domain ? url : relative
167
+ end
168
+
169
+ def [] key
170
+ @qs[key.to_s]
171
+ end
172
+
173
+ def []= key, value
174
+ @qs[key.to_s] = value
175
+ end
176
+
177
+ private
178
+
179
+ def qs_val
180
+ ret = []
181
+ if @qs.keys.length > 0
182
+ ret.push '?' + @qs.keys.sort.map{ |key| "#{key}=#{Url.escape(@qs[key].to_s)}" }.join('&')
183
+ end
184
+ ret.join('')
185
+ end
186
+
187
+ def host_with_port
188
+ %[#{proto}://#{host}#{@port.present? ? ":#{@port}" : ''}]
171
189
  end
172
190
 
173
191
  end