tml 4.3.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.
- checksums.yaml +7 -0
- data/LICENSE +22 -0
- data/README.md +243 -0
- data/Rakefile +9 -0
- data/lib/tml.rb +56 -0
- data/lib/tml/api/client.rb +206 -0
- data/lib/tml/api/post_office.rb +71 -0
- data/lib/tml/application.rb +254 -0
- data/lib/tml/base.rb +116 -0
- data/lib/tml/cache.rb +143 -0
- data/lib/tml/cache_adapters/file.rb +89 -0
- data/lib/tml/cache_adapters/memcache.rb +104 -0
- data/lib/tml/cache_adapters/memory.rb +85 -0
- data/lib/tml/cache_adapters/redis.rb +108 -0
- data/lib/tml/config.rb +410 -0
- data/lib/tml/decorators/base.rb +52 -0
- data/lib/tml/decorators/default.rb +43 -0
- data/lib/tml/decorators/html.rb +102 -0
- data/lib/tml/exception.rb +35 -0
- data/lib/tml/ext/array.rb +86 -0
- data/lib/tml/ext/date.rb +99 -0
- data/lib/tml/ext/fixnum.rb +47 -0
- data/lib/tml/ext/hash.rb +99 -0
- data/lib/tml/ext/string.rb +56 -0
- data/lib/tml/ext/time.rb +89 -0
- data/lib/tml/generators/cache/base.rb +117 -0
- data/lib/tml/generators/cache/file.rb +159 -0
- data/lib/tml/language.rb +175 -0
- data/lib/tml/language_case.rb +105 -0
- data/lib/tml/language_case_rule.rb +76 -0
- data/lib/tml/language_context.rb +117 -0
- data/lib/tml/language_context_rule.rb +56 -0
- data/lib/tml/languages/en.json +1363 -0
- data/lib/tml/logger.rb +109 -0
- data/lib/tml/rules_engine/evaluator.rb +162 -0
- data/lib/tml/rules_engine/parser.rb +65 -0
- data/lib/tml/session.rb +199 -0
- data/lib/tml/source.rb +106 -0
- data/lib/tml/tokenizers/data.rb +96 -0
- data/lib/tml/tokenizers/decoration.rb +204 -0
- data/lib/tml/tokenizers/dom.rb +346 -0
- data/lib/tml/tokens/data.rb +403 -0
- data/lib/tml/tokens/method.rb +61 -0
- data/lib/tml/tokens/transform.rb +223 -0
- data/lib/tml/translation.rb +67 -0
- data/lib/tml/translation_key.rb +178 -0
- data/lib/tml/translator.rb +47 -0
- data/lib/tml/utils.rb +130 -0
- data/lib/tml/version.rb +34 -0
- metadata +121 -0
data/lib/tml/logger.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#--
|
3
|
+
# Copyright (c) 2015 Translation Exchange, Inc
|
4
|
+
#
|
5
|
+
# _______ _ _ _ ______ _
|
6
|
+
# |__ __| | | | | (_) | ____| | |
|
7
|
+
# | |_ __ __ _ _ __ ___| | __ _| |_ _ ___ _ __ | |__ __ _____| |__ __ _ _ __ __ _ ___
|
8
|
+
# | | '__/ _` | '_ \/ __| |/ _` | __| |/ _ \| '_ \| __| \ \/ / __| '_ \ / _` | '_ \ / _` |/ _ \
|
9
|
+
# | | | | (_| | | | \__ \ | (_| | |_| | (_) | | | | |____ > < (__| | | | (_| | | | | (_| | __/
|
10
|
+
# |_|_| \__,_|_| |_|___/_|\__,_|\__|_|\___/|_| |_|______/_/\_\___|_| |_|\__,_|_| |_|\__, |\___|
|
11
|
+
# __/ |
|
12
|
+
# |___/
|
13
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
14
|
+
# a copy of this software and associated documentation files (the
|
15
|
+
# "Software"), to deal in the Software without restriction, including
|
16
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
17
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
18
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
19
|
+
# the following conditions:
|
20
|
+
#
|
21
|
+
# The above copyright notice and this permission notice shall be
|
22
|
+
# included in all copies or substantial portions of the Software.
|
23
|
+
#
|
24
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
25
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
26
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
27
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
28
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
29
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
30
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
31
|
+
#++
|
32
|
+
|
33
|
+
require 'logger'
|
34
|
+
|
35
|
+
module Tml
|
36
|
+
|
37
|
+
def self.logger
|
38
|
+
@logger ||= begin
|
39
|
+
logfile_path = File.expand_path(Tml.config.logger[:path])
|
40
|
+
logfile_dir = logfile_path.split("/")[0..-2].join("/")
|
41
|
+
FileUtils.mkdir_p(logfile_dir) unless File.exist?(logfile_dir)
|
42
|
+
logfile = File.open(logfile_path, 'a')
|
43
|
+
logfile.sync = true
|
44
|
+
Tml::Logger.new(logfile)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class Logger < ::Logger
|
49
|
+
|
50
|
+
def format_message(severity, timestamp, progname, msg)
|
51
|
+
return "" unless Tml.config.logger[:enabled]
|
52
|
+
# TODO: check for severity/level
|
53
|
+
"[#{timestamp.strftime("%D %T")}]: #{" " * stack.size}#{msg}\n"
|
54
|
+
end
|
55
|
+
|
56
|
+
def add(severity, message = nil, progname = nil, &block)
|
57
|
+
return unless Tml.config.logger[:enabled]
|
58
|
+
super
|
59
|
+
end
|
60
|
+
|
61
|
+
def stack
|
62
|
+
@stack ||= []
|
63
|
+
end
|
64
|
+
|
65
|
+
def trace_api_call(path, params, opts = {})
|
66
|
+
#[:client_secret, :access_token].each do |param|
|
67
|
+
# params = params.merge(param => "##filtered##") if params[param]
|
68
|
+
#end
|
69
|
+
if opts[:method] == :post
|
70
|
+
debug("post: [#{path}] #{params.inspect}")
|
71
|
+
else
|
72
|
+
debug("get: #{path}?#{to_query(params)}")
|
73
|
+
end
|
74
|
+
stack.push(caller)
|
75
|
+
t0 = Time.now
|
76
|
+
if block_given?
|
77
|
+
ret = yield
|
78
|
+
end
|
79
|
+
t1 = Time.now
|
80
|
+
stack.pop
|
81
|
+
debug("call took #{t1 - t0} seconds")
|
82
|
+
ret
|
83
|
+
end
|
84
|
+
|
85
|
+
def to_query(hash)
|
86
|
+
query = []
|
87
|
+
hash.each do |key, value|
|
88
|
+
query << "#{key}=#{value}"
|
89
|
+
end
|
90
|
+
query.join('&')
|
91
|
+
end
|
92
|
+
|
93
|
+
def trace(message)
|
94
|
+
debug(message)
|
95
|
+
stack.push(caller)
|
96
|
+
t0 = Time.now
|
97
|
+
if block_given?
|
98
|
+
ret = yield
|
99
|
+
end
|
100
|
+
t1 = Time.now
|
101
|
+
stack.pop
|
102
|
+
debug("execution took #{t1 - t0} seconds")
|
103
|
+
ret
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#--
|
3
|
+
# Copyright (c) 2015 Translation Exchange, Inc
|
4
|
+
#
|
5
|
+
# _______ _ _ _ ______ _
|
6
|
+
# |__ __| | | | | (_) | ____| | |
|
7
|
+
# | |_ __ __ _ _ __ ___| | __ _| |_ _ ___ _ __ | |__ __ _____| |__ __ _ _ __ __ _ ___
|
8
|
+
# | | '__/ _` | '_ \/ __| |/ _` | __| |/ _ \| '_ \| __| \ \/ / __| '_ \ / _` | '_ \ / _` |/ _ \
|
9
|
+
# | | | | (_| | | | \__ \ | (_| | |_| | (_) | | | | |____ > < (__| | | | (_| | | | | (_| | __/
|
10
|
+
# |_|_| \__,_|_| |_|___/_|\__,_|\__|_|\___/|_| |_|______/_/\_\___|_| |_|\__,_|_| |_|\__, |\___|
|
11
|
+
# __/ |
|
12
|
+
# |___/
|
13
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
14
|
+
# a copy of this software and associated documentation files (the
|
15
|
+
# "Software"), to deal in the Software without restriction, including
|
16
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
17
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
18
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
19
|
+
# the following conditions:
|
20
|
+
#
|
21
|
+
# The above copyright notice and this permission notice shall be
|
22
|
+
# included in all copies or substantial portions of the Software.
|
23
|
+
#
|
24
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
25
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
26
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
27
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
28
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
29
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
30
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
31
|
+
#++
|
32
|
+
|
33
|
+
module Tml
|
34
|
+
module RulesEngine
|
35
|
+
|
36
|
+
class Evaluator
|
37
|
+
attr_reader :env, :vars
|
38
|
+
|
39
|
+
def initialize
|
40
|
+
@vars = {}
|
41
|
+
@env = {
|
42
|
+
# McCarthy's Elementary S-functions and Predicates
|
43
|
+
'label' => lambda { |l, r| @vars[l] = r },
|
44
|
+
'quote' => lambda { |expr| expr },
|
45
|
+
'car' => lambda { |list| list[1] },
|
46
|
+
'cdr' => lambda { |list| list.drop(1) },
|
47
|
+
'cons' => lambda { |e, cell| [e] + cell },
|
48
|
+
'eq' => lambda { |l, r| l == r },
|
49
|
+
'atom' => lambda { |expr| [Symbol, String, Fixnum, Float].include?(expr.class) },
|
50
|
+
'cond' => lambda { |c, t, f| evaluate(c) ? evaluate(t) : evaluate(f) },
|
51
|
+
|
52
|
+
# Tml Extensions
|
53
|
+
'=' => lambda { |l, r| l == r }, # ['=', 1, 2]
|
54
|
+
'!=' => lambda { |l, r| l != r }, # ['!=', 1, 2]
|
55
|
+
'<' => lambda { |l, r| l < r }, # ['<', 1, 2]
|
56
|
+
'>' => lambda { |l, r| l > r }, # ['>', 1, 2]
|
57
|
+
'+' => lambda { |l, r| l + r }, # ['+', 1, 2]
|
58
|
+
'-' => lambda { |l, r| l - r }, # ['-', 1, 2]
|
59
|
+
'*' => lambda { |l, r| l * r }, # ['*', 1, 2]
|
60
|
+
'%' => lambda { |l, r| l % r }, # ['%', 14, 10]
|
61
|
+
'mod' => lambda { |l, r| l % r }, # ['mod', '@n', 10]
|
62
|
+
'/' => lambda { |l, r| (l * 1.0) / r }, # ['/', 1, 2]
|
63
|
+
'!' => lambda { |expr| not expr }, # ['!', ['true']]
|
64
|
+
'not' => lambda { |val| not val }, # ['not', ['true']]
|
65
|
+
'&&' => lambda { |*expr| expr.all?{|e| evaluate(e)} }, # ['&&', [], [], ...]
|
66
|
+
'and' => lambda { |*expr| expr.all?{|e| evaluate(e)} }, # ['and', [], [], ...]
|
67
|
+
'||' => lambda { |*expr| expr.any?{|e| evaluate(e)} }, # ['||', [], [], ...]
|
68
|
+
'or' => lambda { |*expr| expr.any?{|e| evaluate(e)} }, # ['or', [], [], ...]
|
69
|
+
'if' => lambda { |c, t, f| evaluate(c) ? evaluate(t) : evaluate(f) }, # ['if', 'cond', 'true', 'false']
|
70
|
+
'let' => lambda { |l, r| @vars[l] = r }, # ['let', 'n', 5]
|
71
|
+
'true' => lambda { true }, # ['true']
|
72
|
+
'false' => lambda { false }, # ['false']
|
73
|
+
|
74
|
+
'date' => lambda { |date| Date.strptime(date, '%Y-%m-%d') }, # ['date', '2010-01-01']
|
75
|
+
'today' => lambda { Time.now.to_date }, # ['today']
|
76
|
+
'time' => lambda { |expr| Time.strptime(expr, '%Y-%m-%d %H:%M:%S') }, # ['time', '2010-01-01 10:10:05']
|
77
|
+
'now' => lambda { Time.now }, # ['now']
|
78
|
+
|
79
|
+
'append' => lambda { |l, r| r.to_s + l.to_s }, # ['append', 'world', 'hello ']
|
80
|
+
'prepend' => lambda { |l, r| l.to_s + r.to_s }, # ['prepend', 'hello ', 'world']
|
81
|
+
'match' => lambda { |search, subject| # ['match', /a/, 'abc']
|
82
|
+
search = regexp_from_string(search)
|
83
|
+
not search.match(subject).nil?
|
84
|
+
},
|
85
|
+
'in' => lambda { |values, search| # ['in', '1,2,3,5..10,20..24', '@n']
|
86
|
+
search = search.to_s.strip
|
87
|
+
values.split(',').each do |e|
|
88
|
+
if e.index('..')
|
89
|
+
bounds = e.strip.split('..')
|
90
|
+
return true if (bounds.first.strip..bounds.last.strip).include?(search)
|
91
|
+
end
|
92
|
+
return true if e.strip == search
|
93
|
+
end
|
94
|
+
false
|
95
|
+
},
|
96
|
+
'within' => lambda { |values, search| # ['within', '0..3', '@n']
|
97
|
+
bounds = values.split('..').map{|d| Integer(d)}
|
98
|
+
(bounds.first..bounds.last).include?(search)
|
99
|
+
},
|
100
|
+
'replace' => lambda { |search, replace, subject| # ['replace', '/^a/', 'v', 'abc']
|
101
|
+
# handle regular expression
|
102
|
+
if /\/i$/.match(search)
|
103
|
+
replace = replace.gsub(/\$(\d+)/, '\\\\\1') # for compatibility with Perl notation
|
104
|
+
end
|
105
|
+
search = regexp_from_string(search)
|
106
|
+
subject.gsub(search, replace)
|
107
|
+
},
|
108
|
+
'count' => lambda { |list| # ['count', '@genders']
|
109
|
+
(list.is_a?(String) ? vars[list] : list).count
|
110
|
+
},
|
111
|
+
'all' => lambda { |list, value| # ['all', '@genders', 'male']
|
112
|
+
list = (list.is_a?(String) ? vars[list] : list)
|
113
|
+
list.is_a?(Array) ? list.all?{|e| e == value} : false
|
114
|
+
},
|
115
|
+
'any' => lambda { |list, value| # ['any', '@genders', 'female']
|
116
|
+
list = (list.is_a?(String) ? vars[list] : list)
|
117
|
+
list.is_a?(Array) ? list.any?{|e| e == value} : false
|
118
|
+
},
|
119
|
+
}
|
120
|
+
end
|
121
|
+
|
122
|
+
def regexp_from_string(str)
|
123
|
+
return Regexp.new(/#{str}/) unless /^\//.match(str)
|
124
|
+
|
125
|
+
str = str.gsub(/^\//, '')
|
126
|
+
|
127
|
+
if /\/i$/.match(str)
|
128
|
+
str = str.gsub(/\/i$/, '')
|
129
|
+
return Regexp.new(/#{str}/i)
|
130
|
+
end
|
131
|
+
|
132
|
+
str = str.gsub(/\/$/, '')
|
133
|
+
Regexp.new(/#{str}/)
|
134
|
+
end
|
135
|
+
|
136
|
+
def reset!
|
137
|
+
@vars = {}
|
138
|
+
end
|
139
|
+
|
140
|
+
def apply(fn, args)
|
141
|
+
raise "undefined symbols #{fn}" unless @env.keys.include?(fn)
|
142
|
+
@env[fn].call(*args)
|
143
|
+
end
|
144
|
+
|
145
|
+
def evaluate(expr)
|
146
|
+
if @env['atom'].call(expr)
|
147
|
+
return @vars[expr] if expr.is_a?(String) and @vars[expr]
|
148
|
+
return expr
|
149
|
+
end
|
150
|
+
|
151
|
+
fn = expr[0]
|
152
|
+
args = expr.drop(1)
|
153
|
+
|
154
|
+
unless %w(quote car cdr cond if && || and or true false let count all any).member?(fn)
|
155
|
+
args = args.map { |a| self.evaluate(a) }
|
156
|
+
end
|
157
|
+
apply(fn, args)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#--
|
3
|
+
# Copyright (c) 2015 Translation Exchange, Inc
|
4
|
+
#
|
5
|
+
# _______ _ _ _ ______ _
|
6
|
+
# |__ __| | | | | (_) | ____| | |
|
7
|
+
# | |_ __ __ _ _ __ ___| | __ _| |_ _ ___ _ __ | |__ __ _____| |__ __ _ _ __ __ _ ___
|
8
|
+
# | | '__/ _` | '_ \/ __| |/ _` | __| |/ _ \| '_ \| __| \ \/ / __| '_ \ / _` | '_ \ / _` |/ _ \
|
9
|
+
# | | | | (_| | | | \__ \ | (_| | |_| | (_) | | | | |____ > < (__| | | | (_| | | | | (_| | __/
|
10
|
+
# |_|_| \__,_|_| |_|___/_|\__,_|\__|_|\___/|_| |_|______/_/\_\___|_| |_|\__,_|_| |_|\__, |\___|
|
11
|
+
# __/ |
|
12
|
+
# |___/
|
13
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
14
|
+
# a copy of this software and associated documentation files (the
|
15
|
+
# "Software"), to deal in the Software without restriction, including
|
16
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
17
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
18
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
19
|
+
# the following conditions:
|
20
|
+
#
|
21
|
+
# The above copyright notice and this permission notice shall be
|
22
|
+
# included in all copies or substantial portions of the Software.
|
23
|
+
#
|
24
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
25
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
26
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
27
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
28
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
29
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
30
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
31
|
+
#++
|
32
|
+
|
33
|
+
module Tml
|
34
|
+
module RulesEngine
|
35
|
+
|
36
|
+
class Parser
|
37
|
+
attr_reader :tokens, :expression
|
38
|
+
|
39
|
+
def initialize(expression)
|
40
|
+
@expression = expression
|
41
|
+
if expression =~ /^\(/
|
42
|
+
@tokens = expression.scan(/[()]|\w+|@\w+|[\+\-\!\|\=>&<\*\/%]+|".*?"|'.*?'/)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def parse
|
47
|
+
return @expression unless tokens
|
48
|
+
token = tokens.shift
|
49
|
+
return nil if token.nil?
|
50
|
+
return parse_list if (token) == '('
|
51
|
+
return token[1..-2].to_s if token =~ /^['"].*/
|
52
|
+
return token.to_i if token =~ /\d+/
|
53
|
+
token.to_s
|
54
|
+
end
|
55
|
+
|
56
|
+
def parse_list
|
57
|
+
list = []
|
58
|
+
list << parse until tokens.empty? or tokens.first == ')'
|
59
|
+
tokens.shift
|
60
|
+
list
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
data/lib/tml/session.rb
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#--
|
3
|
+
# Copyright (c) 2015 Translation Exchange, Inc
|
4
|
+
#
|
5
|
+
# _______ _ _ _ ______ _
|
6
|
+
# |__ __| | | | | (_) | ____| | |
|
7
|
+
# | |_ __ __ _ _ __ ___| | __ _| |_ _ ___ _ __ | |__ __ _____| |__ __ _ _ __ __ _ ___
|
8
|
+
# | | '__/ _` | '_ \/ __| |/ _` | __| |/ _ \| '_ \| __| \ \/ / __| '_ \ / _` | '_ \ / _` |/ _ \
|
9
|
+
# | | | | (_| | | | \__ \ | (_| | |_| | (_) | | | | |____ > < (__| | | | (_| | | | | (_| | __/
|
10
|
+
# |_|_| \__,_|_| |_|___/_|\__,_|\__|_|\___/|_| |_|______/_/\_\___|_| |_|\__,_|_| |_|\__, |\___|
|
11
|
+
# __/ |
|
12
|
+
# |___/
|
13
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
14
|
+
# a copy of this software and associated documentation files (the
|
15
|
+
# "Software"), to deal in the Software without restriction, including
|
16
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
17
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
18
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
19
|
+
# the following conditions:
|
20
|
+
#
|
21
|
+
# The above copyright notice and this permission notice shall be
|
22
|
+
# included in all copies or substantial portions of the Software.
|
23
|
+
#
|
24
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
25
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
26
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
27
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
28
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
29
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
30
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
31
|
+
#++
|
32
|
+
|
33
|
+
module Tml
|
34
|
+
|
35
|
+
def self.session
|
36
|
+
Thread.current[:session] ||= Tml::Session.new
|
37
|
+
end
|
38
|
+
|
39
|
+
class Session
|
40
|
+
# Session Attributes - Move to Session
|
41
|
+
attr_accessor :application, :current_user, :current_locale, :current_language, :current_translator,
|
42
|
+
:current_source, :current_component, :block_options, :cookie_params, :access_token, :tools_enabled
|
43
|
+
|
44
|
+
def self.access_token
|
45
|
+
@access_token
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.access_token=(token)
|
49
|
+
@access_token = token
|
50
|
+
end
|
51
|
+
|
52
|
+
def init(opts = {})
|
53
|
+
return unless Tml.config.enabled? and Tml.config.application
|
54
|
+
|
55
|
+
key = opts[:key] || Tml.config.application[:key]
|
56
|
+
secret = opts[:secret] || Tml.config.application[:secret]
|
57
|
+
host = opts[:host] || Tml.config.application[:host]
|
58
|
+
|
59
|
+
Tml::Session.access_token ||= begin
|
60
|
+
self.access_token = opts[:token] || Tml.config.application[:token]
|
61
|
+
self.access_token ||= opts[:access_token] || Tml.config.application[:access_token]
|
62
|
+
end
|
63
|
+
|
64
|
+
Tml.cache.reset_version
|
65
|
+
|
66
|
+
self.application = Tml.memory.fetch(Tml::Application.cache_key) do
|
67
|
+
Tml::Application.new(:host => host, :key => key, :secret => secret, :access_token => Tml::Session.access_token).fetch
|
68
|
+
end
|
69
|
+
|
70
|
+
if Tml.cache.read_only?
|
71
|
+
self.class.access_token = self.application.access_token
|
72
|
+
end
|
73
|
+
|
74
|
+
# Tml.logger.info(self.cookie_params.inspect)
|
75
|
+
|
76
|
+
self.cookie_params = begin
|
77
|
+
cookie_name = "trex_#{self.application.key}"
|
78
|
+
if opts[:cookies] and opts[:cookies][cookie_name]
|
79
|
+
begin
|
80
|
+
HashWithIndifferentAccess.new(Tml::Utils.decode_and_verify_params(opts[:cookies][cookie_name], secret))
|
81
|
+
rescue Exception => ex
|
82
|
+
Tml.logger.error("Failed to parse tml cookie: #{ex.message}")
|
83
|
+
{}
|
84
|
+
end
|
85
|
+
else
|
86
|
+
{}
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
self.tools_enabled = opts[:tools_enabled]
|
91
|
+
self.current_user = opts[:user]
|
92
|
+
self.current_source = opts[:source] || '/tml/core'
|
93
|
+
self.current_component = opts[:component]
|
94
|
+
self.current_locale = opts[:locale] || self.cookie_params[:locale] || Tml.config.default_locale
|
95
|
+
|
96
|
+
if self.cookie_params['translator']
|
97
|
+
self.current_translator = Tml::Translator.new(self.cookie_params['translator'])
|
98
|
+
end
|
99
|
+
|
100
|
+
# if inline mode don't use any app cache
|
101
|
+
if inline_mode?
|
102
|
+
self.application = self.application.dup
|
103
|
+
self.application.reset_translation_cache
|
104
|
+
end
|
105
|
+
|
106
|
+
if self.current_translator
|
107
|
+
self.current_translator.application = self.application
|
108
|
+
end
|
109
|
+
|
110
|
+
self.current_language = self.application.language(self.current_locale)
|
111
|
+
end
|
112
|
+
|
113
|
+
def tools_enabled?
|
114
|
+
self.tools_enabled
|
115
|
+
end
|
116
|
+
|
117
|
+
def reset
|
118
|
+
self.application= nil
|
119
|
+
self.current_user= nil
|
120
|
+
self.current_language= nil
|
121
|
+
self.current_translator= nil
|
122
|
+
self.current_source= nil
|
123
|
+
self.current_component= nil
|
124
|
+
self.tools_enabled= nil
|
125
|
+
self.block_options= nil
|
126
|
+
end
|
127
|
+
|
128
|
+
def current_language
|
129
|
+
@current_language ||= Tml.config.default_language
|
130
|
+
end
|
131
|
+
|
132
|
+
def application
|
133
|
+
@application ||= Tml::Application.new(:host => Tml::Api::Client::API_HOST)
|
134
|
+
end
|
135
|
+
|
136
|
+
def source_language
|
137
|
+
arr = @block_options || []
|
138
|
+
arr.reverse.each do |opts|
|
139
|
+
return application.language(opts[:locale]) unless opts[:locale].blank?
|
140
|
+
end
|
141
|
+
application.language
|
142
|
+
end
|
143
|
+
|
144
|
+
def target_language
|
145
|
+
arr = @block_options || []
|
146
|
+
arr.reverse.each do |opts|
|
147
|
+
return application.language(opts[:target_locale]) unless opts[:target_locale].nil?
|
148
|
+
end
|
149
|
+
current_language
|
150
|
+
end
|
151
|
+
|
152
|
+
def inline_mode?
|
153
|
+
current_translator and current_translator.inline?
|
154
|
+
end
|
155
|
+
|
156
|
+
#########################################################
|
157
|
+
## Block Options
|
158
|
+
#########################################################
|
159
|
+
|
160
|
+
def push_block_options(opts)
|
161
|
+
(@block_options ||= []).push(opts)
|
162
|
+
end
|
163
|
+
|
164
|
+
def pop_block_options
|
165
|
+
return unless @block_options
|
166
|
+
@block_options.pop
|
167
|
+
end
|
168
|
+
|
169
|
+
def block_options
|
170
|
+
(@block_options ||= []).last || {}
|
171
|
+
end
|
172
|
+
|
173
|
+
def with_block_options(opts)
|
174
|
+
push_block_options(opts)
|
175
|
+
if block_given?
|
176
|
+
ret = yield
|
177
|
+
end
|
178
|
+
pop_block_options
|
179
|
+
ret
|
180
|
+
end
|
181
|
+
|
182
|
+
def current_source_from_block_options
|
183
|
+
arr = @block_options || []
|
184
|
+
arr.reverse.each do |opts|
|
185
|
+
return application.source_by_key(opts[:source]) unless opts[:source].blank?
|
186
|
+
end
|
187
|
+
nil
|
188
|
+
end
|
189
|
+
|
190
|
+
def current_component_from_block_options
|
191
|
+
arr = @block_options || []
|
192
|
+
arr.reverse.each do |opts|
|
193
|
+
return application.component_by_key(opts[:component]) unless opts[:component].blank?
|
194
|
+
end
|
195
|
+
Tml.config.current_component
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
end
|