aerogel-core 1.3.0 → 1.4.10

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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/aerogel-core.gemspec +8 -2
  3. data/app/helpers/assets.rb +22 -8
  4. data/app/helpers/core.rb +82 -0
  5. data/app/helpers/i18n.rb +11 -0
  6. data/app/helpers/icon.rb +12 -0
  7. data/app/helpers/render.rb +89 -17
  8. data/app/helpers/tags.rb +18 -3
  9. data/app/routes/aerogel.rb +30 -0
  10. data/app/routes/core.rb +16 -1
  11. data/app/routes/i18n.rb +14 -0
  12. data/config/application.conf +8 -0
  13. data/config/development/aerogel.conf +9 -0
  14. data/config/production/aerogel.conf +10 -0
  15. data/lib/aerogel/core/application.rb +3 -0
  16. data/lib/aerogel/core/assets.rb +24 -0
  17. data/lib/aerogel/core/cache.rb +72 -0
  18. data/lib/aerogel/core/config.rb +10 -2
  19. data/lib/aerogel/core/core.rb +55 -10
  20. data/lib/aerogel/core/core_ext/array.rb +38 -0
  21. data/lib/aerogel/core/core_ext/hash.rb +48 -0
  22. data/lib/aerogel/core/db.rb +28 -8
  23. data/lib/aerogel/core/db/model.rb +52 -4
  24. data/lib/aerogel/core/errors.rb +23 -1
  25. data/lib/aerogel/core/helpers.rb +1 -1
  26. data/lib/aerogel/core/i18n.rb +134 -0
  27. data/lib/aerogel/core/i18n/number_helper.rb +126 -0
  28. data/lib/aerogel/core/reloader.rb +49 -5
  29. data/lib/aerogel/core/routes.rb +5 -3
  30. data/lib/aerogel/core/routes/namespace.rb +1 -1
  31. data/lib/aerogel/core/version.rb +3 -1
  32. data/locales/core/en.yml +17 -0
  33. data/locales/core/ru.yml +17 -0
  34. data/locales/db/en.yml +25 -0
  35. data/locales/db/ru.yml +24 -0
  36. data/locales/i18n-defaults/en.yml +211 -0
  37. data/locales/i18n-defaults/ru.yml +257 -0
  38. data/rake/console.rake +8 -0
  39. data/views/layouts/application.html.erb +1 -1
  40. data/views/lorem.html.erb +48 -0
  41. metadata +91 -3
  42. data/app/routes/static.rb +0 -7
@@ -1,10 +1,32 @@
1
1
  module Aerogel
2
2
  module Errors
3
3
 
4
- class NotFoundError < StandardError
4
+ module Translated
5
+ def initialize( *args )
6
+ @translation_key = nil
7
+ if args.first.is_a? Symbol
8
+ @translation_key = args.shift
9
+ end
10
+ super( *args )
11
+ end
12
+
13
+ def to_s
14
+ if @translation_key
15
+ Aerogel::I18n.t @translation_key, scope: 'errors.messages'
16
+ else
17
+ super
18
+ end
19
+ end
20
+ end # module Translated
5
21
 
22
+ class NotFoundError < StandardError
23
+ include Translated
6
24
  end # class NotFoundError
7
25
 
26
+ class InvalidOperationError < StandardError
27
+ include Translated
28
+ end # class InvalidOperationError
29
+
8
30
  end # module Errors
9
31
  end # module Aerogel
10
32
 
@@ -19,7 +19,7 @@ private
19
19
  # Sets up reloader for helpers.
20
20
  #
21
21
  def self.setup_reloader(app)
22
- app.use Aerogel::Reloader, ->{ Aerogel.get_resource_list( :app, "helpers/**/*.rb" ) } do |files|
22
+ app.use Aerogel::Reloader, ->{ Aerogel.get_resource_list( :app, "helpers/**/*.rb" ) }, group: :helpers do |files|
23
23
  files.each do |filename|
24
24
  Aerogel.require_into( Aerogel::Helpers, filename )
25
25
  end
@@ -0,0 +1,134 @@
1
+ require 'i18n'
2
+ require 'aerogel/core/i18n/number_helper'
3
+
4
+ # Aerogel::I18n provides localization support for aerogel applications.
5
+ #
6
+ module Aerogel::I18n
7
+
8
+ def self.registered(app)
9
+ # load locales
10
+ reload!
11
+
12
+ # register reloader
13
+ setup_reloader(app) if Aerogel.config.aerogel.reloader?
14
+ end
15
+
16
+
17
+ # Translation helper with chainable key access support.
18
+ # You can call #t using standard i18n way:
19
+ #
20
+ # t 'aerogel.admin.welcome', username: 'John'
21
+ #
22
+ # Or using aerogel syntactic sugar:
23
+ #
24
+ # t.aerogel.admin.welcome username: 'John'
25
+ #
26
+ def self.t( *args )
27
+ if args.size > 0
28
+ # puts "** I18n.t original t: #{args}"
29
+ ::I18n.t( *args )
30
+ else
31
+ # puts "** I18n.t chainable t: #{args}"
32
+ Chainable.new( *args )
33
+ end
34
+ end
35
+
36
+ def self.l( *args )
37
+ if args.first.nil? && args.second.is_a?( Hash ) && args.second.key?(:default)
38
+ default_value = args.second[:default]
39
+ if default_value.is_a? Symbol
40
+ ::I18n.t default_value
41
+ else
42
+ default_value
43
+ end
44
+ else
45
+ ::I18n.l( *args )
46
+ end
47
+ end
48
+
49
+ def self.locale( *args )
50
+ ::I18n.locale( *args )
51
+ end
52
+
53
+ def self.locale=( *args )
54
+ ::I18n.send :'locale=', *args
55
+ end
56
+
57
+ def self.default_locale
58
+ ::I18n.default_locale
59
+ end
60
+ def self.available_locales
61
+ ::I18n.available_locales
62
+ end
63
+
64
+ # Human file size helper.
65
+ #
66
+ extend NumberHelper
67
+ #def self.number_to_human_size( *args )
68
+ # ActiveSupport::NumberHelper.number_to_human_size( *args )
69
+ #end
70
+
71
+ private
72
+
73
+ # Sets up reloader for locales.
74
+ #
75
+ def self.setup_reloader(app)
76
+ app.use Aerogel::Reloader, ->{ get_locale_files } do |files|
77
+ reload! files
78
+ end
79
+ end
80
+
81
+ # Returns list of locale translation files.
82
+ #
83
+ def self.get_locale_files
84
+ Aerogel.get_resource_list( :locales, "**/*.yml" )
85
+ end
86
+
87
+ # Reload locales.
88
+ #
89
+ def self.reload!( files = nil )
90
+ ::I18n.load_path = files || get_locale_files
91
+ ::I18n.reload!
92
+ ::I18n.available_locales = Aerogel.config.locales.enabled! if Aerogel.config.locales.enabled?
93
+ if Aerogel.config.locales.default?
94
+ ::I18n.default_locale = Aerogel.config.locales.default!
95
+ else
96
+ ::I18n.default_locale = ::I18n.available_locales.first
97
+ end
98
+ end
99
+
100
+
101
+ # Chainable #t helper support class.
102
+ # Example:
103
+ # t.aerogel.admin.welcome # => t 'aerogel.admin.welcome'
104
+ # t.aerogel.admin.welcome username: 'John' # => t 'aerogel.admin.welcome', username: 'John'
105
+ #
106
+ class Chainable
107
+ def initialize( *args )
108
+ @path = []
109
+ call( *args ) if args.size > 0
110
+ end
111
+
112
+ def method_missing( name, *args )
113
+ @path << name.to_sym
114
+ if args.size > 0
115
+ call( *args )
116
+ else
117
+ self
118
+ end
119
+ end
120
+
121
+ def call( *args )
122
+ ::I18n.t translation_key, *args
123
+ end
124
+
125
+ def to_s()
126
+ ::I18n.t translation_key
127
+ end
128
+
129
+ def translation_key
130
+ @path.join(".")
131
+ end
132
+ end # class Chainable
133
+
134
+ end # module Aerogel::I18n
@@ -0,0 +1,126 @@
1
+ module Aerogel::I18n
2
+ module NumberHelper
3
+
4
+ def number_with_delimiter(number, options = {})
5
+ options.symbolize_keys!
6
+
7
+ options[:delimiter] = ERB::Util.html_escape(options[:delimiter]) if options[:delimiter]
8
+ options[:separator] = ERB::Util.html_escape(options[:separator]) if options[:separator]
9
+
10
+ begin
11
+ Float(number)
12
+ rescue ArgumentError, TypeError
13
+ if options[:raise]
14
+ raise # InvalidNumberError, number
15
+ else
16
+ return number
17
+ end
18
+ end
19
+
20
+ defaults = ::I18n.translate(:'number.format', :locale => options[:locale], :default => {})
21
+ options = options.reverse_merge(defaults)
22
+
23
+ parts = number.to_s.to_str.split('.')
24
+ parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
25
+ parts.join(options[:separator]).html_safe
26
+
27
+ end
28
+
29
+ DECIMAL_UNITS = {0 => :unit, 1 => :ten, 2 => :hundred, 3 => :thousand, 6 => :million, 9 => :billion, 12 => :trillion, 15 => :quadrillion,
30
+ -1 => :deci, -2 => :centi, -3 => :mili, -6 => :micro, -9 => :nano, -12 => :pico, -15 => :femto}
31
+
32
+ def number_with_precision(number, options = {})
33
+ options.symbolize_keys!
34
+
35
+ number = begin
36
+ Float(number)
37
+ rescue ArgumentError, TypeError
38
+ if options[:raise]
39
+ raise # InvalidNumberError, number
40
+ else
41
+ return number
42
+ end
43
+ end
44
+
45
+ defaults = ::I18n.translate(:'number.format', :locale => options[:locale], :default => {})
46
+ precision_defaults = ::I18n.translate(:'number.precision.format', :locale => options[:locale], :default => {})
47
+ defaults = defaults.merge(precision_defaults)
48
+
49
+ options = options.reverse_merge(defaults) # Allow the user to unset default values: Eg.: :significant => false
50
+ precision = options.delete :precision
51
+ significant = options.delete :significant
52
+ strip_insignificant_zeros = options.delete :strip_insignificant_zeros
53
+
54
+ if significant and precision > 0
55
+ if number == 0
56
+ digits, rounded_number = 1, 0
57
+ else
58
+ digits = (Math.log10(number.abs) + 1).floor
59
+ rounded_number = (BigDecimal.new(number.to_s) / BigDecimal.new((10 ** (digits - precision)).to_f.to_s)).round.to_f * 10 ** (digits - precision)
60
+ digits = (Math.log10(rounded_number.abs) + 1).floor # After rounding, the number of digits may have changed
61
+ end
62
+ precision -= digits
63
+ precision = precision > 0 ? precision : 0 #don't let it be negative
64
+ else
65
+ rounded_number = BigDecimal.new(number.to_s).round(precision).to_f
66
+ end
67
+ formatted_number = number_with_delimiter("%01.#{precision}f" % rounded_number, options)
68
+ if strip_insignificant_zeros
69
+ escaped_separator = Regexp.escape(options[:separator])
70
+ formatted_number.sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '').html_safe
71
+ else
72
+ formatted_number
73
+ end
74
+
75
+ end
76
+
77
+ STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb]
78
+
79
+ # TODO: use NumberHelper from 'activesupport ~> 4.0',
80
+ # at the moment it is incompatible with mongoid,
81
+ #
82
+ #
83
+ def number_to_human_size(number, options = {})
84
+ options.symbolize_keys!
85
+
86
+ number = begin
87
+ Float(number)
88
+ rescue ArgumentError, TypeError
89
+ if options[:raise]
90
+ raise # InvalidNumberError, number
91
+ else
92
+ return number
93
+ end
94
+ end
95
+
96
+ defaults = ::I18n.translate(:'number.format', :locale => options[:locale], :default => {})
97
+ human = ::I18n.translate(:'number.human.format', :locale => options[:locale], :default => {})
98
+ defaults = defaults.merge(human)
99
+
100
+ options = options.reverse_merge(defaults)
101
+ #for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
102
+ options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros)
103
+
104
+ storage_units_format = ::I18n.translate(:'number.human.storage_units.format', :locale => options[:locale], :raise => true)
105
+
106
+ base = options[:prefix] == :si ? 1000 : 1024
107
+
108
+ if number.to_i < base
109
+ unit = ::I18n.translate(:'number.human.storage_units.units.byte', :locale => options[:locale], :count => number.to_i, :raise => true)
110
+ storage_units_format.gsub(/%n/, number.to_i.to_s).gsub(/%u/, unit).html_safe
111
+ else
112
+ max_exp = STORAGE_UNITS.size - 1
113
+ exponent = (Math.log(number) / Math.log(base)).to_i # Convert to base
114
+ exponent = max_exp if exponent > max_exp # we need this to avoid overflow for the highest unit
115
+ number /= base ** exponent
116
+
117
+ unit_key = STORAGE_UNITS[exponent]
118
+ unit = ::I18n.translate(:"number.human.storage_units.units.#{unit_key}", :locale => options[:locale], :count => number, :raise => true)
119
+
120
+ formatted_number = number_with_precision(number, options)
121
+ storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit).html_safe
122
+ end
123
+ end
124
+
125
+ end # module NumberHelper
126
+ end # module Aerogel::I18n
@@ -2,6 +2,9 @@
2
2
  #
3
3
  module Aerogel
4
4
  class Reloader
5
+
6
+ attr_accessor :files, :group, :opts, :action
7
+
5
8
  # Use as middleware:
6
9
  #
7
10
  # # single file
@@ -17,12 +20,36 @@ class Reloader
17
20
  # files.each{|f| load f}
18
21
  # end
19
22
  #
20
- def initialize( app, files, &blk )
23
+ # # named groups of files
24
+ # use Aerogel::Reloader, "routes/*.rb", group: :routes do |files|
25
+ # files.each{|f| load f }
26
+ # end
27
+ #
28
+ # # adding observer on a named group
29
+ # use Aerogel::Reloader, :routes, before: true do |files|
30
+ # # do more stuff before group :routes is reloaded
31
+ # end
32
+ #
33
+ # Valid options are:
34
+ # :group => name group of files
35
+ # :before => if true invoke action block before group is reloaded
36
+ # :after => if true invoke action block after group is reloaded
37
+ #
38
+ #
39
+ def initialize( app, files, opts = {}, &blk )
21
40
  @app = app
22
- @files = files
41
+ if files.is_a? Symbol
42
+ @group = files
43
+ @files = nil
44
+ else
45
+ @files = files
46
+ @group = opts[:group]
47
+ end
48
+ @opts = opts
23
49
  @action = blk
24
- @file_list = file_list( @files )
25
- @signature = signature( @file_list )
50
+ @file_list = file_list( @files ) if @files
51
+ @signature = signature( @file_list ) if @file_list
52
+ Aerogel::Reloader.reloaders << self
26
53
  end
27
54
 
28
55
  def call( env )
@@ -30,18 +57,35 @@ class Reloader
30
57
  @app.call( env )
31
58
  end
32
59
 
60
+ def self.reloaders
61
+ @reloaders ||= []
62
+ end
63
+
33
64
  private
34
65
 
35
66
  # Checks if files are changed and reloads if so.
36
67
  #
37
68
  def check!
69
+ return unless @files
38
70
  @file_list = file_list( @files )
39
71
  new_signature = signature( @file_list )
40
72
  if @signature != new_signature
41
73
  # reload file list
42
- puts "* Aerogel::Reloader reloading: #{@file_list}"
74
+ puts "* Aerogel::Reloader reloading: #{@file_list}, group: #{@group}"
75
+ if @group
76
+ # invoke :before group actions
77
+ Aerogel::Reloader.reloaders.select{|r| r.group == @group && r.opts[:before] }.each do |r|
78
+ r.action.call @file_list
79
+ end
80
+ end
43
81
  @action.call @file_list
44
82
  @signature = new_signature
83
+ if @group
84
+ # invoke :after group actions
85
+ Aerogel::Reloader.reloaders.select{|r| r.group == @group && r.opts[:after] }.each do |r|
86
+ r.action.call @file_list
87
+ end
88
+ end
45
89
  end
46
90
  end
47
91
 
@@ -6,7 +6,7 @@ module Aerogel::Routes
6
6
  def self.registered(app)
7
7
  reset!(app)
8
8
  # load routes
9
- Aerogel.get_resource_list( :app, "routes/**/*.rb" ).reverse.each do |filename|
9
+ Aerogel.get_reverse_resource_list( :app, "routes/**/*.rb" ).each do |filename|
10
10
  Aerogel.require_into( Aerogel::Application, filename )
11
11
  end
12
12
 
@@ -42,10 +42,12 @@ private
42
42
  # Sets up reloader for routes.
43
43
  #
44
44
  def self.setup_reloader(app)
45
- app.use Aerogel::Reloader, ->{ Aerogel.get_resource_list( :app, "routes/**/*.rb" ) } do |files|
45
+ app.use Aerogel::Reloader,
46
+ ->{ Aerogel.get_reverse_resource_list( :app, "routes/**/*.rb" ) },
47
+ group: :routes do |files|
46
48
  # reset routes
47
49
  reset!(app)
48
- files.reverse.each do |filename|
50
+ files.each do |filename|
49
51
  Aerogel.require_into( Aerogel::Application, filename )
50
52
  end
51
53
  end
@@ -14,7 +14,7 @@ class Namespace
14
14
 
15
15
  def prefixed( method, *args, &block )
16
16
  options = Hash === args.last ? args.pop : {}
17
- routes = [*(args.pop || '')]
17
+ routes = [*(args.pop || '*')]
18
18
  routes, args = routes+args, [] unless method == :route
19
19
  routes.map!{|r| @prefix_path+r }
20
20
  routes = [routes] if method == :route
@@ -1,3 +1,5 @@
1
1
  module Aerogel
2
- VERSION = '1.3.0'
2
+ module Core
3
+ VERSION = '1.4.10'
4
+ end # module Core
3
5
  end
@@ -0,0 +1,17 @@
1
+ en:
2
+ "true": true
3
+ "false": false
4
+ "on": on
5
+ "On": On
6
+ "off": off
7
+ "Off": Off
8
+ "yes": yes
9
+ "Yes": Yes
10
+ "no": no
11
+ "No": No
12
+ "and": and
13
+ "And": And
14
+ "or": or
15
+ "Or": Or
16
+ "never": never
17
+ "Never": Never