bizside 2.0.1

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 (89) hide show
  1. checksums.yaml +7 -0
  2. data/app/assets/images/jquery-treeTable/images/toggle-collapse-dark.png +0 -0
  3. data/app/assets/images/jquery-treeTable/images/toggle-collapse-light.png +0 -0
  4. data/app/assets/images/jquery-treeTable/images/toggle-expand-dark.png +0 -0
  5. data/app/assets/images/jquery-treeTable/images/toggle-expand-light.png +0 -0
  6. data/app/assets/javascripts/bizside.js +1 -0
  7. data/app/assets/javascripts/jquery-treeTable/jquery.treeTable.js +400 -0
  8. data/app/assets/stylesheets/bizside.css +3 -0
  9. data/app/assets/stylesheets/jquery-treeTable/jquery.treeTable.css.erb +55 -0
  10. data/lib/bizside/acl/access_control_utils.rb +36 -0
  11. data/lib/bizside/acl/available_helper.rb +65 -0
  12. data/lib/bizside/acl/controller_helper.rb +15 -0
  13. data/lib/bizside/acl.rb +6 -0
  14. data/lib/bizside/active_record_logger.rb +3 -0
  15. data/lib/bizside/audit/job_logger.rb +14 -0
  16. data/lib/bizside/audit/logger.rb +35 -0
  17. data/lib/bizside/audit_log.rb +158 -0
  18. data/lib/bizside/cache/entry.rb +112 -0
  19. data/lib/bizside/cache/file_store.rb +167 -0
  20. data/lib/bizside/cache/store.rb +237 -0
  21. data/lib/bizside/cache_util.rb +47 -0
  22. data/lib/bizside/cache_utils.rb +10 -0
  23. data/lib/bizside/carrierwave.rb +48 -0
  24. data/lib/bizside/config.rb +63 -0
  25. data/lib/bizside/configurations/mail.rb +37 -0
  26. data/lib/bizside/configurations/prefix.rb +25 -0
  27. data/lib/bizside/configurations/storage.rb +28 -0
  28. data/lib/bizside/coverage/launch.rb +25 -0
  29. data/lib/bizside/coverage/rcov_formatter.rb +13 -0
  30. data/lib/bizside/cron_validator.rb +62 -0
  31. data/lib/bizside/cucumber.rb +1 -0
  32. data/lib/bizside/engine.rb +4 -0
  33. data/lib/bizside/file_converter.rb +56 -0
  34. data/lib/bizside/file_uploader.rb +71 -0
  35. data/lib/bizside/gengou.rb +46 -0
  36. data/lib/bizside/gengou.yml +5 -0
  37. data/lib/bizside/hanaita_conf.rb +88 -0
  38. data/lib/bizside/implicit_ftps.rb +29 -0
  39. data/lib/bizside/itamae_conf.rb +186 -0
  40. data/lib/bizside/job_utils.rb +285 -0
  41. data/lib/bizside/log_analyzer.rb +122 -0
  42. data/lib/bizside/mailer.rb +56 -0
  43. data/lib/bizside/query_builder.rb +78 -0
  44. data/lib/bizside/railtie.rb +80 -0
  45. data/lib/bizside/record_has_warnings.rb +4 -0
  46. data/lib/bizside/resque.rb +141 -0
  47. data/lib/bizside/rsync.rb +40 -0
  48. data/lib/bizside/safe_pty.rb +17 -0
  49. data/lib/bizside/shib_utils.rb +18 -0
  50. data/lib/bizside/show_exceptions.rb +18 -0
  51. data/lib/bizside/sql_utils.rb +45 -0
  52. data/lib/bizside/string_io.rb +39 -0
  53. data/lib/bizside/string_utils.rb +157 -0
  54. data/lib/bizside/task_helper.rb +263 -0
  55. data/lib/bizside/tasks.rb +6 -0
  56. data/lib/bizside/test_help.rb +17 -0
  57. data/lib/bizside/uploader/content_type_validator.rb +39 -0
  58. data/lib/bizside/uploader/default_extensions.yml +15 -0
  59. data/lib/bizside/uploader/exif.rb +43 -0
  60. data/lib/bizside/uploader/extension_whitelist.rb +26 -0
  61. data/lib/bizside/uploader/filename_validator.rb +31 -0
  62. data/lib/bizside/user_agent/action_view/action_view_4.rb +56 -0
  63. data/lib/bizside/user_agent/action_view/use_variant.rb +4 -0
  64. data/lib/bizside/user_agent/action_view.rb +10 -0
  65. data/lib/bizside/user_agent/controller_helper.rb +51 -0
  66. data/lib/bizside/user_agent.rb +108 -0
  67. data/lib/bizside/validations.rb +8 -0
  68. data/lib/bizside/version.rb +3 -0
  69. data/lib/bizside/view_helper.rb +10 -0
  70. data/lib/bizside/warning.rb +24 -0
  71. data/lib/bizside/yes.rb +16 -0
  72. data/lib/bizside.rb +96 -0
  73. data/lib/cron_validator.rb +3 -0
  74. data/lib/gengou.rb +3 -0
  75. data/lib/job_utils.rb +3 -0
  76. data/lib/query_builder.rb +3 -0
  77. data/lib/record_has_warnings.rb +3 -0
  78. data/lib/sql_utils.rb +3 -0
  79. data/lib/string_utils.rb +3 -0
  80. data/lib/user_agent.rb +3 -0
  81. data/lib/yes.rb +3 -0
  82. data/rails/locales/ja.yml +12 -0
  83. data/validations/collection_presence_validator.rb +15 -0
  84. data/validations/email_validator.rb +1 -0
  85. data/validations/ip_address_validator.rb +22 -0
  86. data/validations/tel_validator.rb +28 -0
  87. data/validations/url_validator.rb +30 -0
  88. data/validations/zip_validator.rb +35 -0
  89. metadata +467 -0
@@ -0,0 +1,158 @@
1
+ require_relative 'audit/logger'
2
+
3
+ module Bizside
4
+ class AuditLog
5
+
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def call(env)
11
+ start = Time.now.strftime('%Y-%m-%dT%H:%M:%S.%3N%z')
12
+ @status, @headers, @response = @app.call(env)
13
+ stop = Time.now.strftime('%Y-%m-%dT%H:%M:%S.%3N%z')
14
+ exception = env[Bizside::ShowExceptions::BIZSIDE_EXCEPTION_ENV_KEY]
15
+
16
+ if env['BIZSIDE_SUPPRESS_AUDIT']
17
+ return @status, @headers, @response
18
+ end
19
+
20
+ if Bizside.rails_env&.development?
21
+ return @status, @headers, @response if env['REQUEST_URI'] =~ /\/[^\/]+\/assets\/.*/
22
+ elsif Bizside.rails_env&.test?
23
+ return @status, @headers, @response
24
+ end
25
+
26
+ info = build_loginfo(env, start, stop, @status, exception)
27
+ logger.record(info)
28
+
29
+ return @status, @headers, @response
30
+ end
31
+
32
+ private
33
+
34
+ def logger
35
+ @logger ||= Bizside::Audit::Logger.logger
36
+ end
37
+
38
+ def build_loginfo(env, start, stop, status, exception)
39
+ info = {
40
+ time: start,
41
+ add_on_name: detect_add_on_name(env),
42
+ feature: detect_feature(env),
43
+ action: detect_action(env),
44
+ data: detect_data(env),
45
+ interactive: detect_interactive(env),
46
+ company: detect_company(env),
47
+ user: detect_user(env),
48
+ employee_code: detect_employee_code(env),
49
+ department: detect_department(env),
50
+ project: detect_project(env),
51
+ server_name: env['SERVER_NAME'],
52
+ server_address: ENV['HOSTNAME'] || env['SERVER_ADDR'], # nginx と apache で異なる
53
+ server_port: env['SERVER_PORT'],
54
+ scheme: env['rack.url_scheme'],
55
+ path: env['PATH_INFO'],
56
+ referrer: env['HTTP_REFERER'],
57
+ request_method: env['REQUEST_METHOD'],
58
+ request_uri: env['BIZSIDE_REQUEST_URI'].presence || env['REQUEST_URI'],
59
+ remote_address: env['REMOTE_ADDR'],
60
+ status: status,
61
+ started_at: start,
62
+ finished_at: stop,
63
+ device: detect_device(env),
64
+ user_agent: detect_user_agent(env),
65
+ exception: detect_exception(exception),
66
+ exception_message: detect_exception_message(exception),
67
+ exception_backtrace: detect_exception_backtrace(exception)
68
+ }
69
+
70
+ info
71
+ end
72
+
73
+ def detect_company(env)
74
+ env['BIZSIDE_COMPANY']
75
+ end
76
+
77
+ def detect_user(env)
78
+ ret = env['BIZSIDE_USER']
79
+ ret ||= Bizside::ShibUtils._get_bizside_user(env)
80
+
81
+ if ret.to_s.empty?
82
+ if defined?(Devise)
83
+ warden = env['warden']
84
+ if warden.authenticate?
85
+ auth_user = warden.send(warden.config[:default_scope])
86
+ ret = auth_user.email
87
+ end
88
+ end
89
+ end
90
+
91
+ ret
92
+ end
93
+
94
+ def detect_add_on_name(env)
95
+ ret = env['BIZSIDE_ADD_ON_NAME']
96
+ ret ||= Bizside.config.add_on_name
97
+ ret
98
+ end
99
+
100
+ def detect_feature(env)
101
+ env['BIZSIDE_FEATURE']
102
+ end
103
+
104
+ def detect_action(env)
105
+ env['BIZSIDE_ACTION']
106
+ end
107
+
108
+ def detect_data(env)
109
+ env['BIZSIDE_DATA']
110
+ end
111
+
112
+ def detect_interactive(env)
113
+ env['BIZSIDE_INTERACTIVE']
114
+ end
115
+
116
+ def detect_department(env)
117
+ env['BIZSIDE_DEPARTMENT']
118
+ end
119
+
120
+ def detect_project(env)
121
+ env['BIZSIDE_PROJECT']
122
+ end
123
+
124
+ def detect_device(env)
125
+ env['BIZSIDE_DEVICE']
126
+ end
127
+
128
+ def detect_user_agent(env)
129
+ ret = env['BIZSIDE_USER_AGENT']
130
+ ret ||= env['HTTP_USER_AGENT']
131
+ ret
132
+ end
133
+
134
+ def detect_employee_code(env)
135
+ ret = env['BIZSIDE_EMPLOYEE_CODE']
136
+ ret
137
+ end
138
+
139
+ def detect_exception(exception)
140
+ return '' unless exception
141
+
142
+ exception.class.name
143
+ end
144
+
145
+ def detect_exception_message(exception)
146
+ return '' unless exception
147
+
148
+ exception.to_s
149
+ end
150
+
151
+ def detect_exception_backtrace(exception)
152
+ return '' unless exception
153
+
154
+ exception.backtrace.join("\n")
155
+ end
156
+
157
+ end
158
+ end
@@ -0,0 +1,112 @@
1
+ module Bizside
2
+ module Cache
3
+ class Entry
4
+ DEFAULT_COMPRESS_LIMIT = 16.kilobytes
5
+
6
+ def initialize(value, options = {})
7
+ if should_compress?(value, options)
8
+ @value = compress(value)
9
+ @compressed = true
10
+ else
11
+ @value = value
12
+ end
13
+
14
+ @created_at = Time.now.to_f
15
+ @expires_in = options[:expires_in]
16
+ @expires_in = @expires_in.to_f if @expires_in
17
+ end
18
+
19
+ def value
20
+ convert_version_4beta1_entry! if defined?(@v)
21
+ compressed? ? uncompress(@value) : @value
22
+ end
23
+
24
+ def expired?
25
+ convert_version_4beta1_entry! if defined?(@v)
26
+ @expires_in && @created_at + @expires_in <= Time.now.to_f
27
+ end
28
+
29
+ def expires_at
30
+ @expires_in ? @created_at + @expires_in : nil
31
+ end
32
+
33
+ def expires_at=(value)
34
+ if value
35
+ @expires_in = value.to_f - @created_at
36
+ else
37
+ @expires_in = nil
38
+ end
39
+ end
40
+
41
+ def size
42
+ if defined?(@s)
43
+ @s
44
+ else
45
+ case value
46
+ when NilClass
47
+ 0
48
+ when String
49
+ @value.bytesize
50
+ else
51
+ @s = Marshal.dump(@value).bytesize
52
+ end
53
+ end
54
+ end
55
+
56
+ def dup_value!
57
+ convert_version_4beta1_entry! if defined?(@v)
58
+
59
+ if @value && !compressed? && !(@value.is_a?(Numeric) || @value == true || @value == false)
60
+ if @value.is_a?(String)
61
+ @value = @value.dup
62
+ else
63
+ @value = Marshal.load(Marshal.dump(@value))
64
+ end
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ def should_compress?(value, options)
71
+ if value && options[:compress]
72
+ compress_threshold = options[:compress_threshold] || DEFAULT_COMPRESS_LIMIT
73
+ serialized_value_size = (value.is_a?(String) ? value : Marshal.dump(value)).bytesize
74
+
75
+ return true if serialized_value_size >= compress_threshold
76
+ end
77
+
78
+ false
79
+ end
80
+
81
+ def compressed?
82
+ defined?(@compressed) ? @compressed : false
83
+ end
84
+
85
+ def compress(value)
86
+ Zlib::Deflate.deflate(Marshal.dump(value))
87
+ end
88
+
89
+ def uncompress(value)
90
+ Marshal.load(Zlib::Inflate.inflate(value))
91
+ end
92
+
93
+ def convert_version_4beta1_entry!
94
+ if defined?(@v)
95
+ @value = @v
96
+ remove_instance_variable(:@v)
97
+ end
98
+
99
+ if defined?(@c)
100
+ @compressed = @c
101
+ remove_instance_variable(:@c)
102
+ end
103
+
104
+ if defined?(@x) && @x
105
+ @created_at ||= Time.now.to_f
106
+ @expires_in = @x - @created_at
107
+ remove_instance_variable(:@x)
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,167 @@
1
+ require 'bizside/cache/store'
2
+
3
+ module Bizside
4
+ module Cache
5
+ class FileStore < Store
6
+
7
+ attr_reader :cache_path
8
+
9
+ DIR_FORMATTER = "%03X"
10
+ FILENAME_MAX_SIZE = 228 # max filename size on file system is 255, minus room for timestamp and random characters appended by Tempfile (used by atomic write)
11
+ FILEPATH_MAX_SIZE = 900 # max is 1024, plus some room
12
+ EXCLUDED_DIRS = ['.', '..'].freeze
13
+
14
+ def initialize(cache_path, options = nil)
15
+ super(options)
16
+ @cache_path = cache_path.to_s
17
+ end
18
+
19
+ def clear(options = nil)
20
+ root_dirs = Dir.entries(cache_path).reject {|f| (EXCLUDED_DIRS + [".gitkeep"]).include?(f)}
21
+ FileUtils.rm_r(root_dirs.collect{|f| File.join(cache_path, f)})
22
+ end
23
+
24
+ def cleanup(options = nil)
25
+ options = merged_options(options)
26
+ search_dir(cache_path) do |fname|
27
+ key = file_path_key(fname)
28
+ entry = read_entry(key, options)
29
+ delete_entry(key, options) if entry && entry.expired?
30
+ end
31
+ end
32
+
33
+ def increment(name, amount = 1, options = nil)
34
+ modify_value(name, amount, options)
35
+ end
36
+
37
+ def decrement(name, amount = 1, options = nil)
38
+ modify_value(name, -amount, options)
39
+ end
40
+
41
+ def delete_matched(matcher, options = nil)
42
+ options = merged_options(options)
43
+ instrument(:delete_matched, matcher.inspect) do
44
+ matcher = key_matcher(matcher, options)
45
+ search_dir(cache_path) do |path|
46
+ key = file_path_key(path)
47
+ delete_entry(key, options) if key.match(matcher)
48
+ end
49
+ end
50
+ end
51
+
52
+ protected
53
+
54
+ def read_entry(key, options)
55
+ file_name = key_file_path(key)
56
+ if File.exist?(file_name)
57
+ File.open(file_name) { |f| Marshal.load(f) }
58
+ end
59
+ rescue => e
60
+ nil
61
+ end
62
+
63
+ def write_entry(key, entry, options)
64
+ file_name = key_file_path(key)
65
+ return false if options[:unless_exist] && File.exist?(file_name)
66
+ ensure_cache_path(File.dirname(file_name))
67
+ File.atomic_write(file_name, cache_path) {|f| Marshal.dump(entry, f)}
68
+ true
69
+ end
70
+
71
+ def delete_entry(key, options)
72
+ file_name = key_file_path(key)
73
+ if File.exist?(file_name)
74
+ begin
75
+ File.delete(file_name)
76
+ delete_empty_directories(File.dirname(file_name))
77
+ true
78
+ rescue => e
79
+ raise e if File.exist?(file_name)
80
+ false
81
+ end
82
+ end
83
+ end
84
+
85
+ private
86
+
87
+ def lock_file(file_name, &block)
88
+ if File.exist?(file_name)
89
+ File.open(file_name, 'r+') do |f|
90
+ begin
91
+ f.flock File::LOCK_EX
92
+ yield
93
+ ensure
94
+ f.flock File::LOCK_UN
95
+ end
96
+ end
97
+ else
98
+ yield
99
+ end
100
+ end
101
+
102
+ def key_file_path(key)
103
+ if key.size > FILEPATH_MAX_SIZE
104
+ key = Digest::MD5.hexdigest(key)
105
+ end
106
+
107
+ fname = URI.encode_www_form_component(key)
108
+ hash = Zlib.adler32(fname)
109
+ hash, dir_1 = hash.divmod(0x1000)
110
+ dir_2 = hash.modulo(0x1000)
111
+ fname_paths = []
112
+
113
+ begin
114
+ fname_paths << fname[0, FILENAME_MAX_SIZE]
115
+ fname = fname[FILENAME_MAX_SIZE..-1]
116
+ end until fname.blank?
117
+
118
+ File.join(cache_path, DIR_FORMATTER % dir_1, DIR_FORMATTER % dir_2, *fname_paths)
119
+ end
120
+
121
+ def file_path_key(path)
122
+ fname = path[cache_path.to_s.size..-1].split(File::SEPARATOR, 4).last
123
+ URI.decode_www_form_component(fname, Encoding::UTF_8)
124
+ end
125
+
126
+ def delete_empty_directories(dir)
127
+ return if File.realpath(dir) == File.realpath(cache_path)
128
+ if Dir.entries(dir).reject {|f| EXCLUDED_DIRS.include?(f)}.empty?
129
+ Dir.delete(dir) rescue nil
130
+ delete_empty_directories(File.dirname(dir))
131
+ end
132
+ end
133
+
134
+ def ensure_cache_path(path)
135
+ FileUtils.makedirs(path) unless File.exist?(path)
136
+ end
137
+
138
+ def search_dir(dir, &callback)
139
+ return if !File.exist?(dir)
140
+ Dir.foreach(dir) do |d|
141
+ next if EXCLUDED_DIRS.include?(d)
142
+ name = File.join(dir, d)
143
+ if File.directory?(name)
144
+ search_dir(name, &callback)
145
+ else
146
+ callback.call name
147
+ end
148
+ end
149
+ end
150
+
151
+ def modify_value(name, amount, options)
152
+ file_name = key_file_path(namespaced_key(name, options))
153
+
154
+ lock_file(file_name) do
155
+ options = merged_options(options)
156
+
157
+ if num = read(name, options)
158
+ num = num.to_i + amount
159
+ write(name, num, options)
160
+ num
161
+ end
162
+ end
163
+ end
164
+
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,237 @@
1
+ require 'bizside/cache/entry'
2
+
3
+ module Bizside
4
+ module Cache
5
+ class Store
6
+
7
+ attr_reader :options
8
+
9
+ def initialize(options = nil)
10
+ @options = options ? options.dup : {}
11
+ end
12
+
13
+ def fetch(name, options = nil)
14
+ if block_given?
15
+ options = merged_options(options)
16
+ key = namespaced_key(name, options)
17
+
18
+ cached_entry = find_cached_entry(key, name, options) unless options[:force]
19
+ entry = handle_expired_entry(cached_entry, key, options)
20
+
21
+ if entry
22
+ get_entry_value(entry, name, options)
23
+ else
24
+ save_block_result_to_cache(name, options) { |_name| yield _name }
25
+ end
26
+ else
27
+ read(name, options)
28
+ end
29
+ end
30
+
31
+ def read(name, options = nil)
32
+ options = merged_options(options)
33
+ key = namespaced_key(name, options)
34
+ instrument(:read, name, options) do |payload|
35
+ entry = read_entry(key, options)
36
+ if entry
37
+ if entry.expired?
38
+ delete_entry(key, options)
39
+ payload[:hit] = false if payload
40
+ nil
41
+ else
42
+ payload[:hit] = true if payload
43
+ entry.value
44
+ end
45
+ else
46
+ payload[:hit] = false if payload
47
+ nil
48
+ end
49
+ end
50
+ end
51
+
52
+ def read_multi(*names)
53
+ options = names.extract_options!
54
+ options = merged_options(options)
55
+ results = {}
56
+ names.each do |name|
57
+ key = namespaced_key(name, options)
58
+ entry = read_entry(key, options)
59
+ if entry
60
+ if entry.expired?
61
+ delete_entry(key, options)
62
+ else
63
+ results[name] = entry.value
64
+ end
65
+ end
66
+ end
67
+ results
68
+ end
69
+
70
+ def fetch_multi(*names)
71
+ options = names.extract_options!
72
+ options = merged_options(options)
73
+ results = read_multi(*names, options)
74
+
75
+ names.each_with_object({}) do |name, memo|
76
+ memo[name] = results.fetch(name) do
77
+ value = yield name
78
+ write(name, value, options)
79
+ value
80
+ end
81
+ end
82
+ end
83
+
84
+ def write(name, value, options = nil)
85
+ options = merged_options(options)
86
+
87
+ instrument(:write, name, options) do
88
+ entry = Bizside::Cache::Entry.new(value, options)
89
+ write_entry(namespaced_key(name, options), entry, options)
90
+ end
91
+ end
92
+
93
+ def delete(name, options = nil)
94
+ options = merged_options(options)
95
+
96
+ instrument(:delete, name) do
97
+ delete_entry(namespaced_key(name, options), options)
98
+ end
99
+ end
100
+
101
+ def exist?(name, options = nil)
102
+ options = merged_options(options)
103
+
104
+ instrument(:exist?, name) do
105
+ entry = read_entry(namespaced_key(name, options), options)
106
+ (entry && !entry.expired?) || false
107
+ end
108
+ end
109
+
110
+ def delete_matched(matcher, options = nil)
111
+ raise NotImplementedError.new("does not support delete_matched")
112
+ end
113
+
114
+ def increment(name, amount = 1, options = nil)
115
+ raise NotImplementedError.new("does not support increment")
116
+ end
117
+
118
+ def decrement(name, amount = 1, options = nil)
119
+ raise NotImplementedError.new("does not support decrement")
120
+ end
121
+
122
+ def cleanup(options = nil)
123
+ raise NotImplementedError.new("does not support cleanup")
124
+ end
125
+
126
+ def clear(options = nil)
127
+ raise NotImplementedError.new("does not support clear")
128
+ end
129
+
130
+ protected
131
+
132
+ def key_matcher(pattern, options)
133
+ prefix = options[:namespace].is_a?(Proc) ? options[:namespace].call : options[:namespace]
134
+ if prefix
135
+ source = pattern.source
136
+ if source.start_with?('^')
137
+ source = source[1, source.length]
138
+ else
139
+ source = ".*#{source[0, source.length]}"
140
+ end
141
+ Regexp.new("^#{Regexp.escape(prefix)}:#{source}", pattern.options)
142
+ else
143
+ pattern
144
+ end
145
+ end
146
+
147
+ def read_entry(key, options)
148
+ raise NotImplementedError.new
149
+ end
150
+
151
+ def write_entry(key, entry, options)
152
+ raise NotImplementedError.new
153
+ end
154
+
155
+ def delete_entry(key, options)
156
+ raise NotImplementedError.new
157
+ end
158
+
159
+ private
160
+
161
+ def merged_options(call_options)
162
+ if call_options
163
+ options.merge(call_options)
164
+ else
165
+ options.dup
166
+ end
167
+ end
168
+
169
+ def expanded_key(key)
170
+ return key.cache_key.to_s if key.respond_to?(:cache_key)
171
+
172
+ case key
173
+ when Array
174
+ if key.size > 1
175
+ key = key.collect{|element| expanded_key(element)}
176
+ else
177
+ key = key.first
178
+ end
179
+ when Hash
180
+ key = key.sort_by { |k,_| k.to_s }.collect{|k,v| "#{k}=#{v}"}
181
+ end
182
+
183
+ key.to_param
184
+ end
185
+
186
+ def namespaced_key(key, options)
187
+ key = expanded_key(key)
188
+ namespace = options[:namespace] if options
189
+ prefix = namespace.is_a?(Proc) ? namespace.call : namespace
190
+ key = "#{prefix}:#{key}" if prefix
191
+ key
192
+ end
193
+
194
+ def instrument(operation, key, options = nil)
195
+ payload = { :key => key }
196
+ payload.merge!(options) if options.is_a?(Hash)
197
+ ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload){ yield(payload) }
198
+ end
199
+
200
+ def find_cached_entry(key, name, options)
201
+ instrument(:read, name, options) do |payload|
202
+ payload[:super_operation] = :fetch if payload
203
+ read_entry(key, options)
204
+ end
205
+ end
206
+
207
+ def handle_expired_entry(entry, key, options)
208
+ if entry && entry.expired?
209
+ race_ttl = options[:race_condition_ttl].to_i
210
+ if (race_ttl > 0) && (Time.now.to_f - entry.expires_at <= race_ttl)
211
+ entry.expires_at = Time.now + race_ttl
212
+ write_entry(key, entry, :expires_in => race_ttl * 2)
213
+ else
214
+ delete_entry(key, options)
215
+ end
216
+ entry = nil
217
+ end
218
+ entry
219
+ end
220
+
221
+ def get_entry_value(entry, name, options)
222
+ instrument(:fetch_hit, name, options) { |payload| }
223
+ entry.value
224
+ end
225
+
226
+ def save_block_result_to_cache(name, options)
227
+ result = instrument(:generate, name, options) do |payload|
228
+ yield(name)
229
+ end
230
+
231
+ write(name, result, options)
232
+ result
233
+ end
234
+
235
+ end
236
+ end
237
+ end
@@ -0,0 +1,47 @@
1
+ module Bizside
2
+ module CacheUtil
3
+
4
+ def fetch(key, options = {})
5
+ if block_given?
6
+ action = cache.exist?(key) ? 'READ' : 'WRITE'
7
+ output_log "#{action} CACHE: #{key}"
8
+ cache.fetch(key, options) do
9
+ yield
10
+ end
11
+ else
12
+ output_log "READ CACHE: #{key}"
13
+ cache.fetch(key, options)
14
+ end
15
+ end
16
+
17
+ def delete(key)
18
+ output_log "CLEAR CACHE: #{key}"
19
+ cache.delete(key)
20
+ end
21
+
22
+ def delete_matched(matcher)
23
+ output_log "CLEAR CACHE: #{matcher}"
24
+ cache.delete_matched(matcher)
25
+ end
26
+
27
+ def clear(options = nil)
28
+ output_log "CLEAR ALL CACHE"
29
+ cache.clear(options)
30
+ end
31
+
32
+ def cache
33
+ raise 'サブクラスで実装'
34
+ end
35
+
36
+ private
37
+
38
+ def output_log message
39
+ if defined?(Rails) && Rails.logger
40
+ Rails.logger.info message
41
+ else
42
+ puts message
43
+ end
44
+ end
45
+
46
+ end
47
+ end