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,78 @@
1
+ module Bizside
2
+ class QueryBuilder
3
+
4
+ attr_reader :sql, :params
5
+
6
+ def initialize
7
+ @sql = ''
8
+ @params = []
9
+ @indent = 0
10
+ end
11
+
12
+ def append(*args)
13
+ if args.size == 1
14
+ if args[0].is_a?(Array)
15
+ append(*args[0])
16
+ elsif args[0].is_a?(QueryBuilder)
17
+ append(args[0].to_array)
18
+ else
19
+ append_sql(args[0])
20
+ end
21
+ else
22
+ args.each_with_index do |arg, i|
23
+ if i == 0
24
+ append_sql(arg)
25
+ else
26
+ @params << arg
27
+ end
28
+ end
29
+ end
30
+
31
+ self
32
+ end
33
+
34
+ def and(*args)
35
+ append_sql('and (')
36
+
37
+ if block_given?
38
+ @indent += 1
39
+ yield self
40
+ @indent -= 1
41
+ else
42
+ append(*args)
43
+ end
44
+
45
+ append_sql(')')
46
+ end
47
+
48
+ def or(*args)
49
+ append_sql('or (')
50
+
51
+ if block_given?
52
+ @indent += 1
53
+ yield self
54
+ @indent -= 1
55
+ else
56
+ append(*args)
57
+ end
58
+
59
+ append_sql(')')
60
+ end
61
+
62
+ def to_array
63
+ [@sql] + @params
64
+ end
65
+
66
+ def to_a
67
+ to_array
68
+ end
69
+
70
+ private
71
+
72
+ def append_sql(sql)
73
+ @indent.times { @sql << ' ' }
74
+ @sql << sql
75
+ @sql << "\n"
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,80 @@
1
+ require_relative 'coverage/launch'
2
+
3
+ module Bizside
4
+ class Railtie < ::Rails::Railtie
5
+
6
+ # ロケールファイル
7
+ initializer 'bizside-i18n' do |app|
8
+ Bizside::Railtie.instance_eval do
9
+ pattern = pattern_from(app.config.i18n.available_locales)
10
+ add("rails/locales/#{pattern}.yml")
11
+ end
12
+ end
13
+
14
+ # ビューのヘルパーメソッド
15
+ initializer 'view_helper' do
16
+ require_relative 'view_helper'
17
+
18
+ ActiveSupport.on_load(:action_view) do
19
+ include Bizside::ViewHelper
20
+ end
21
+ end
22
+
23
+ # 警告バリデーション
24
+ if Bizside.config.warning_validation.enabled?
25
+ require_relative 'warning'
26
+
27
+ initializer 'warning_validation' do
28
+ ActiveSupport.on_load :active_record do
29
+ include Bizside::Warning
30
+ end
31
+ end
32
+ end
33
+
34
+ if Bizside.config.user_agent.enabled?
35
+ require_relative 'user_agent'
36
+
37
+ initializer 'user_agent' do
38
+ require_relative 'user_agent/action_view'
39
+
40
+ ActiveSupport.on_load(:action_controller) do
41
+ include Bizside::UserAgent::ControllerHelper
42
+ end
43
+ end
44
+ end
45
+
46
+ if Bizside.config.acl.enabled?
47
+ require_relative 'acl'
48
+
49
+ initializer 'acl' do
50
+ ActiveSupport.on_load(:action_controller) do
51
+ include Bizside::Acl::ControllerHelper
52
+ end
53
+ ActiveSupport.on_load(:action_view) do
54
+ include Bizside::Acl::AvailableHelper
55
+ end
56
+ end
57
+ end
58
+
59
+ unless Bizside.config.active_record_logger.enabled?
60
+ initializer 'active_record_logger' do
61
+ ActiveSupport.on_load(:active_record) do
62
+ require_relative 'active_record_logger'
63
+ end
64
+ end
65
+ end
66
+
67
+ protected
68
+
69
+ def self.add(pattern)
70
+ files = Dir[File.join(File.dirname(__FILE__), '../..', pattern)]
71
+ I18n.load_path.concat(files)
72
+ end
73
+
74
+ def self.pattern_from(args)
75
+ array = Array(args || [])
76
+ array.blank? ? '*' : "{#{array.join ','}}"
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,4 @@
1
+ module Bizside
2
+ class RecordHasWarnings < Exception
3
+ end
4
+ end
@@ -0,0 +1,141 @@
1
+ module Bizside
2
+ module Resque
3
+ end
4
+ end
5
+
6
+ require 'resque'
7
+ require 'resque/worker'
8
+ require 'resque/failure/base'
9
+ require 'resque/failure/multiple'
10
+ require 'resque/failure/redis'
11
+ require_relative 'audit/job_logger'
12
+
13
+ {
14
+ yaml: ['config/resque.yml', 'config/redis.yml'],
15
+ json: ['config/resque.json', 'config/redis.json']
16
+ }.each do |format, file_candidates|
17
+ file_candidates.each do |file|
18
+ resque_file = File.join(File.expand_path(ENV['RAILS_ROOT'] || '.'), file)
19
+ next unless File.exist?(resque_file)
20
+
21
+ resque_config = ERB.new(File.read(resque_file), 0, '-').result
22
+
23
+ case format
24
+ when :yaml
25
+ Resque.redis = YAML.load(resque_config)[Bizside.env]
26
+ break
27
+ when :json
28
+ Resque.redis = ActiveSupport::JSON.decode(resque_config)[Bizside.env]
29
+ break
30
+ else
31
+ raise "不正なResque設定ファイルです。#{file}"
32
+ end
33
+ end
34
+ end
35
+
36
+ Resque.redis.namespace = "resque:#{Bizside.config.add_on_name}:#{Bizside.env}"
37
+
38
+ if defined?(Resque::Scheduler)
39
+ Resque::Scheduler.dynamic = true
40
+ end
41
+
42
+ # tmp/stop.txt が存在する場合は一時停止する
43
+ module Resque
44
+ class Worker
45
+
46
+ alias_method :reserve_without_stop_txt, :reserve
47
+
48
+ def reserve
49
+ stop_file_path = File.join('tmp', 'stop.txt')
50
+ if File.exist?(stop_file_path)
51
+ puts "#{Resque.redis.namespace} #{stop_file_path} が存在するため一時停止します。"
52
+ nil
53
+ else
54
+ reserve_without_stop_txt
55
+ end
56
+ end
57
+
58
+ end
59
+ end
60
+
61
+ # resque-webのエラーメッセージ文字化けに対するパッチ
62
+ module Resque
63
+ module Failure
64
+ class Redis
65
+
66
+ def save
67
+ data = {
68
+ :failed_at => UTF8Util.clean(Time.now.strftime("%Y/%m/%d %H:%M:%S %Z")),
69
+ :payload => payload,
70
+ :exception => exception.class.to_s,
71
+ :error => exception.to_s, #UTF8Util.clean(exception.to_s), UTF8Util.cleanを呼ぶと文字化けする
72
+ :backtrace => filter_backtrace(Array(exception.backtrace)),
73
+ :worker => worker.to_s,
74
+ :queue => queue
75
+ }
76
+ data = Resque.encode(data)
77
+ Resque.redis.rpush(:failed, data)
78
+ end
79
+
80
+ end
81
+ end
82
+ end
83
+
84
+ # エラーをログに出力
85
+ module Resque
86
+ module Failure
87
+ class LogOutput < Base
88
+ def save
89
+ Bizside.logger.error [
90
+ "[FATAL] Resque #{queue}:#{worker}",
91
+ "#{payload}",
92
+ "#{exception.class} #{exception.to_s}",
93
+ "#{Array(exception.backtrace).join("\n")}"
94
+ ].join("\n")
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ # エラーをLTSV形式で専用ログに出力
101
+ module Resque
102
+ module Failure
103
+ class JobAuditLog < Base
104
+
105
+ def save
106
+ info = build_loginfo
107
+ return info if Bizside.rails_env&.test?
108
+
109
+ logger.record(info)
110
+
111
+ info
112
+ end
113
+
114
+ private
115
+
116
+ def logger
117
+ @logger ||= Bizside::Audit::JobLogger.logger
118
+ end
119
+
120
+ def build_loginfo
121
+ info = {
122
+ time: Time.now.strftime('%Y-%m-%dT%H:%M:%S.%3N%z'),
123
+ add_on_name: Bizside.config.add_on_name,
124
+ class: payload['class'],
125
+ args: payload['args'].to_s,
126
+ queue: queue,
127
+ worker: worker.to_s,
128
+ exception: exception.class,
129
+ exception_message: exception.to_s,
130
+ exception_backtrace: Array(exception.backtrace)[0..10].join("\n") # Get only the top 10 because there are many traces.
131
+ }
132
+ info
133
+ end
134
+
135
+ end
136
+ end
137
+ end
138
+
139
+ Resque::Failure::Multiple.configure do |multi|
140
+ multi.classes = [Resque::Failure::Redis, Resque::Failure::LogOutput, Resque::Failure::JobAuditLog]
141
+ end
@@ -0,0 +1,40 @@
1
+ module Bizside
2
+ module Rsync
3
+
4
+ def self.cleanup_old_dirs(backup_dirs, generations)
5
+ if backup_dirs.size > generations
6
+ puts '--------------------'
7
+ while backup_dirs.size > generations
8
+ old_backup_dir = backup_dirs.shift
9
+ puts "古いバックアップを削除します。#{old_backup_dir}"
10
+ FileUtils.rm_r(old_backup_dir, :force => true)
11
+ end
12
+ puts '--------------------'
13
+ end
14
+ end
15
+
16
+ def self.next_generation(backup_dir)
17
+ running_dir = backup_dir + '.running'
18
+ failure_dir = backup_dir + '.failed'
19
+
20
+ begin
21
+ FileUtils.ln_s(backup_dir, running_dir)
22
+ yield
23
+ rescue => e
24
+ FileUtils.ln_s(backup_dir, failure_dir)
25
+ raise e
26
+ ensure
27
+ FileUtils.rm_f(running_dir)
28
+ end
29
+ end
30
+
31
+ # YYYYMMDDHHMMSS形式
32
+ # .failed や .running は除外する
33
+ def self.get_backup_dirs(backup_base_dir)
34
+ ret = Dir::glob(File.join(backup_base_dir, '2*')).reject{|dir| File.basename(dir).index('.') }
35
+ ret = ret.sort
36
+ ret
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,17 @@
1
+ require 'pty'
2
+
3
+ module Bizside::SafePty
4
+
5
+ def self.spawn command, &block
6
+ PTY.spawn(command) do |r, w, p|
7
+ begin
8
+ yield r, w, p
9
+ rescue Errno::EIO
10
+ ensure
11
+ Process.wait p
12
+ end
13
+ end
14
+
15
+ $?.exitstatus
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ # Shibboleth環境に関するユーティリティ
2
+ class Bizside::ShibUtils
3
+ LOGOUT_URL = '/Shibboleth.sso/Logout'
4
+
5
+ def self.get_bizside_user(request)
6
+ ret = _get_bizside_user(request.env)
7
+ ret ||= _get_bizside_user(request.headers)
8
+ ret
9
+ end
10
+
11
+ def self._get_bizside_user(hash)
12
+ ret = hash['mail']
13
+ ret ||= hash['HTTP_X_BIZSIDE_USER']
14
+ ret ||= hash['X-BIZSIDE-USER']
15
+ ret
16
+ end
17
+
18
+ end
@@ -0,0 +1,18 @@
1
+ module Bizside
2
+ class ShowExceptions
3
+
4
+ BIZSIDE_EXCEPTION_ENV_KEY = 'bizside.exception'
5
+
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def call(env)
11
+ @app.call(env)
12
+ rescue Exception => exception
13
+ env[BIZSIDE_EXCEPTION_ENV_KEY] = exception # 発生した例外を保持
14
+ raise exception
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,45 @@
1
+ module Bizside
2
+ class SqlUtils
3
+
4
+ # LIKE検索用に検索文字列をエスケープします。
5
+ def self.escape_search(str)
6
+ str.gsub(/\\/, '\\\\\\\\').gsub(/%/, '\%').gsub(/_/, '\_')
7
+ end
8
+
9
+ def self.like(columns, query_string, options = {})
10
+ target_columns = columns
11
+ unless target_columns.is_a?(Array)
12
+ target_columns = [target_columns]
13
+ end
14
+
15
+ sql = []
16
+ sql[0] = '('
17
+
18
+ query_string.gsub(/ /, ' ').split.each_with_index do |s, i|
19
+ like = self.escape_search(s)
20
+
21
+ sql[0] << ' or ' if i > 0
22
+ sql[0] << '('
23
+
24
+ target_columns.each_with_index do |column, j|
25
+ sql[0] << ' or ' if j > 0
26
+ sql[0] << "#{column} like ?"
27
+
28
+ if options.fetch(:backward_match, false)
29
+ sql << like + '%'
30
+ elsif options.fetch(:forward_match, false)
31
+ sql << '%' + like
32
+ else
33
+ sql << '%' + like + '%'
34
+ end
35
+ end
36
+
37
+ sql[0] << ')'
38
+ end
39
+
40
+ sql[0] << ')'
41
+ sql
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,39 @@
1
+ module Bizside
2
+ class StringIO < StringIO
3
+ attr_accessor :base_dir
4
+ attr_accessor :fullpath
5
+ attr_accessor :content_type
6
+ attr_accessor :file_size
7
+ attr_accessor :md5
8
+
9
+ def initialize(string = '', mode = 'r+')
10
+ super(string, mode)
11
+ begin
12
+ self.md5 = Digest::MD5.hexdigest(self.read)
13
+ rescue
14
+ #失敗しても何もしない。
15
+ ensure
16
+ self.rewind
17
+ end
18
+ end
19
+
20
+ def original_filename
21
+ fullpath ? File.basename(fullpath) : ''
22
+ end
23
+
24
+ def original_dirname
25
+ fullpath ? File.dirname(fullpath) : ''
26
+ end
27
+
28
+ def relative_dirname
29
+ if fullpath
30
+ relpath = fullpath.sub(/^#{Regexp.quote(base_dir)}/,'').sub(/^\//,'')
31
+ File.dirname(relpath) == '.' ? '' : File.dirname(relpath)
32
+ else
33
+ ''
34
+ end
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1,157 @@
1
+ require 'nkf'
2
+
3
+ module Bizside
4
+ class StringUtils
5
+ Characters = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a
6
+
7
+ def self.create_random_alpha_string length, case_sensitive = false
8
+ chars = ('a'..'z').to_a
9
+ chars += ('A'..'Z').to_a if case_sensitive
10
+ chars.sample(length).join
11
+ end
12
+
13
+ def self.create_random_string(number)
14
+ (Array.new(number.to_i) do
15
+ Characters[rand(Characters.size)]
16
+ end
17
+ ).join
18
+ end
19
+
20
+ def self.to_hiragana(s)
21
+ return s if is_empty(s)
22
+ NKF::nkf('-Ww --hiragana', s)
23
+ end
24
+
25
+ def self.to_katakana(s)
26
+ return s if is_empty(s)
27
+ NKF::nkf('-Ww --katakana', s)
28
+ end
29
+
30
+ def self.to_zen(s)
31
+ return s if is_empty(s)
32
+ NKF::nkf('-WwXm0', s)
33
+ end
34
+
35
+ def self.to_han(s)
36
+ return s if is_empty(s)
37
+ NKF::nkf('-Wwxm0Z0', s)
38
+ end
39
+
40
+ def self.sjis_to_utf8(s)
41
+ NKF.nkf('-Swx', s)
42
+ end
43
+
44
+ def self.utf8_to_sjis(s)
45
+ NKF.nkf('-Wsx', s)
46
+ end
47
+
48
+ def self.is_empty(s)
49
+ s.nil? or s.empty?
50
+ end
51
+
52
+ def self.equal(s1, s2)
53
+ if is_empty(s1) and is_empty(s2)
54
+ true
55
+ else
56
+ s1 == s2
57
+ end
58
+ end
59
+
60
+ def self.current_time_string(now = nil)
61
+ now = Time.now unless now
62
+ now.instance_eval { '%s%03d' % [strftime('%Y%m%d%H%M%S'), (usec / 1000.0).round] }
63
+ end
64
+
65
+ def self.is_user_password(value,minimum,maximum)
66
+ value =~ /^[!-~]{#{minimum},#{maximum}}$/u
67
+ end
68
+
69
+ def self.is_not_user_password(value,minimum,maximum)
70
+ ! is_user_password(value,minimum,maximum)
71
+ end
72
+
73
+ def self.is_login_id(value)
74
+ return nil if value =~ /\.{2,}/
75
+ value =~ /^[0-9a-z_\.\-]{1,50}$/u
76
+ end
77
+
78
+ def self.is_not_login_id(value)
79
+ ! is_login_id(value)
80
+ end
81
+
82
+ # HTMLタグを除去した文書を返す
83
+ def self.remove_html_tag(str)
84
+ return nil unless str
85
+ str=str.dup
86
+ str.sub!(/<[^<>]*>/,"") while /<[^<>]*>/ =~ str
87
+ str
88
+ end
89
+
90
+ # リッチテキストの改行を保ったまま、HTMLタグを除去した文書を返す
91
+ def self.remove_rich_html_tag(str)
92
+ return nil unless str
93
+
94
+ ret = str.gsub(/<div[^>]*>/, "\n")
95
+ ret = remove_html_tag(ret)
96
+ ret
97
+ end
98
+
99
+ # 指定した長さのランダム英数字文字列を返す。a-zA-Z0-9。62種類。
100
+ def self.rand_string(length = 8)
101
+ ret = []
102
+ length.times do |i|
103
+ ret[i] = Characters[rand(Characters.size)]
104
+ end
105
+ ret = ret.join
106
+
107
+ return ret if ret =~ /^(?=.*?[a-z])(?=.*?\d).*+$/iu
108
+
109
+ # 英字と数字が最低1文字を含むランダム英数字文字列を返すようにする
110
+ alphabets = ('a'..'z').to_a + ('A'..'Z').to_a
111
+ numerics = (0..9).to_a
112
+ ranges = (0...length).to_a
113
+ ret[ranges.slice!(rand(ranges.size))] = alphabets[rand(alphabets.size)]
114
+ ret[ranges.slice!(rand(ranges.size))] = numerics[rand(numerics.size)].to_s
115
+
116
+ ret
117
+ end
118
+
119
+ # URLからクエリストリングを除外して文字列を返す。
120
+ # https://www.example.com?foo=bar #=> https://www.example.com
121
+ def self.exclude_query_string(string)
122
+ return string unless string.include?("?")
123
+ string[/^.*(?=\?)/]
124
+ end
125
+
126
+ # 複数個の全角スペースを1個に圧縮する
127
+ def self.compress_doble_byte_space(string)
128
+ return nil unless string
129
+ string.gsub(/ +/, ' ')
130
+ end
131
+
132
+ # 文字列中に含まれる全角ハイフンっぽい文字を、指定した文字に一括置換する
133
+ def self.replace_char_like_hyphen_to(string, to: "\u30FC")
134
+ # U+002D Hyphen-Minus
135
+ # U+00AD Soft Hyphen
136
+ # U+02D7 Modifier Letter Minus Sign
137
+ # U+2010 Hyphen
138
+ # U+2011 Non-Breaking Hyphen
139
+ # U+2012 Figure Dash
140
+ # U+2013 En Dash
141
+ # U+2014 Em Dash
142
+ # U+2015 Horizontal Bar
143
+ # U+2043 Hyphen Bullet
144
+ # U+2212 Minus Sign
145
+ # U+2796 Heavy Minus Sign
146
+ # U+30FC Katakana-Hiragana Prolonged Sound Mark
147
+ # U+FE58 Small Em Dash
148
+ # U+FE63 Small Hyphen-Minus
149
+ # U+FF0D Fullwidth Hyphen-Minus
150
+ # U+FF70 Halfwidth Katakana-Hiragana Prolonged Sound Mark
151
+ string.gsub(
152
+ /[\u002D\u00AD\u02D7\u2010\u2011\u2012\u2013\u2014\u2015\u2043\u2212\u2796\u30FC\uFE58\uFE63\uFF0D\uFF70]/,
153
+ to
154
+ )
155
+ end
156
+ end
157
+ end