lhj-tools 0.1.1 → 0.1.5

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.
@@ -0,0 +1,40 @@
1
+ require 'yaml'
2
+ require 'lhj/helper/oss_config'
3
+
4
+ module Lhj
5
+ class LocalConfig
6
+ def config_file
7
+ File.join(Lhj::Config.instance.home_dir, config_file_name)
8
+ end
9
+
10
+ def config_file_name
11
+ 'localizable_config.yml'
12
+ end
13
+
14
+ def syn_config_file
15
+ Lhj::OSS::Helper.instance.down_load(config_file_name, config_file)
16
+ end
17
+
18
+ def load_config
19
+ syn_config_file unless File.exist?(config_file)
20
+ YAML.load_file(config_file)
21
+ end
22
+
23
+ def get_col_by_name(file_name, col_name = 'csv_key_col')
24
+ m = config
25
+ col = m[col_name]
26
+ fo = m['read_targets'].find{ |o| /#{o['csv_file']}/ =~ file_name }
27
+ col = fo[col_name] if fo
28
+ col
29
+ end
30
+
31
+ def config
32
+ @config ||= load_config
33
+ end
34
+
35
+ def self.instance
36
+ @instance ||= new
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ require 'yaml'
3
+ require 'lhj/config'
4
+
5
+ module Lhj
6
+ class OSSConfig
7
+ def self.config_file
8
+ file = 'oss_config.yml'
9
+ File.expand_path("#{Lhj::Config.instance.home_dir}/#{file}")
10
+ end
11
+
12
+ def self.config
13
+ @yaml ||= YAML.load_file(config_file)
14
+ end
15
+
16
+ def self.oss_endpoint
17
+ config['oss_endpoint']
18
+ end
19
+
20
+ def self.oss_access_key_id
21
+ config['oss_access_key_id']
22
+ end
23
+
24
+ def self.oss_access_key_secret
25
+ config['oss_access_key_secret']
26
+ end
27
+
28
+ def self.oss_bucket
29
+ config['oss_bucket']
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,43 @@
1
+ require 'aliyun/oss'
2
+ require 'lhj/helper/oss_config'
3
+
4
+ module Lhj
5
+ class OSS
6
+ class Helper
7
+ def initialize
8
+ @client = Aliyun::OSS::Client.new(endpoint: Lhj::OSSConfig.oss_endpoint,
9
+ access_key_id: Lhj::OSSConfig.oss_access_key_id,
10
+ access_key_secret: Lhj::OSSConfig.oss_access_key_secret)
11
+ @bucket = @client.get_bucket(Lhj::OSSConfig.oss_bucket)
12
+ end
13
+
14
+ def url_path
15
+ "http://#{Lhj::OSSConfig.oss_bucket}.#{Lhj::OSSConfig.oss_endpoint}"
16
+ end
17
+
18
+ def upload(key, file)
19
+ @bucket.put_object(key, :file => file)
20
+ end
21
+
22
+ def down_load(key, file, &block)
23
+ @bucket.get_object(key, :file => file, &block)
24
+ end
25
+
26
+ def object_url(key)
27
+ @bucket.object_url(key, false)
28
+ end
29
+
30
+ def list
31
+ @bucket.list_objects
32
+ end
33
+
34
+ def delete(key)
35
+ @bucket.delete_object(key)
36
+ end
37
+
38
+ def self.instance
39
+ @instance ||= new
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,49 @@
1
+ require 'lhj/config'
2
+
3
+ module Lhj
4
+ class Trans
5
+ class Helper
6
+ def self.instance
7
+ @instance ||= new
8
+ end
9
+
10
+ def yaml_file
11
+ File.join(Lhj::Config.instance.home_dir, 'zh2hant.yml')
12
+ end
13
+
14
+ def load_trans_map
15
+ require 'yaml'
16
+ down_load_yaml unless File.exist?(yaml_file)
17
+ contents = YAML.safe_load(File.open(yaml_file))
18
+ contents.to_hash
19
+ end
20
+
21
+ def down_load_yaml
22
+ require 'open-uri'
23
+ URI.open('http://aomi-ios-repo.oss-cn-shenzhen.aliyuncs.com/zh2hant.yml') do |i|
24
+ File.open(yaml_file, 'w+') do |f|
25
+ f.write(i.read)
26
+ end
27
+ end
28
+ end
29
+
30
+ def trans_zh_cn_str(input)
31
+ @trans_map_invert ||= load_trans_map.invert
32
+ out = []
33
+ input.each_char do |c|
34
+ out << (@trans_map_invert[c] || c)
35
+ end
36
+ out.join('')
37
+ end
38
+
39
+ def trans_zh_hk_str(input)
40
+ @trans_map ||= load_trans_map
41
+ out = []
42
+ input.each_char do |c|
43
+ out << (@trans_map[c] || c)
44
+ end
45
+ out.join('')
46
+ end
47
+ end
48
+ end
49
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Lhj
4
4
  module Tools
5
- VERSION = "0.1.1"
5
+ VERSION = "0.1.5"
6
6
  end
7
7
  end
data/lib/lhj/tools.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
-
3
2
  require_relative "tools/version"
4
3
 
5
4
  module Lhj
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lhj
4
+ class Tree
5
+ # Render nodes as files paths explorer
6
+ class DirectoryRenderer
7
+ MARKERS = {
8
+ unicode: {
9
+ branch: '├──',
10
+ leaf: '└──',
11
+ pipe: '│'
12
+ },
13
+ ansi: {
14
+ branch: '|--',
15
+ leaf: '`--',
16
+ pipe: '|'
17
+ }
18
+ }.freeze
19
+
20
+ def initialize(nodes, options = {})
21
+ @nodes = nodes
22
+ @indent = options.fetch(:indent, 4)
23
+ @pipe_mark = MARKERS[:unicode][:pipe] + ' ' * [@indent - 1, 0].max
24
+ @space_mark = ' ' * @indent
25
+ end
26
+
27
+ def render
28
+ @nodes.reduce([]) do |acc, node|
29
+ render_node(acc, node, @pipe_mark, @space_mark)
30
+ end.join('')
31
+ end
32
+
33
+ private
34
+
35
+ def render_node(acc, node, pipe_mark, space_mark)
36
+ acc << node.prefix.gsub(/:pipe/, pipe_mark).gsub(/:space/, space_mark)
37
+ unless node.root?
38
+ acc << MARKERS[:unicode][node.leaf? ? :leaf : :branch]
39
+ acc << ' '
40
+ end
41
+ acc << node.name.to_s + "\n"
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pathname'
4
+
5
+ require 'lhj/tree/node'
6
+
7
+ module Lhj
8
+ class Tree
9
+ # Walk and collect nodes from hash data strcture.
10
+ #
11
+ # @api public
12
+ class HashWalker
13
+ attr_reader :nodes
14
+
15
+ attr_reader :files_count
16
+
17
+ attr_reader :dirs_count
18
+
19
+ def initialize(options = {})
20
+ @nodes = []
21
+ @files_count = 0
22
+ @dirs_count = 0
23
+ @level = options.fetch(:level) { -1 }
24
+ @file_limit = options.fetch(:file_limit) { - 1 }
25
+ end
26
+
27
+ def traverse(data)
28
+ walk(data, Pathname.new(''), '', 0, false)
29
+ end
30
+
31
+ def walk(data, parent_path, prefix, level, is_last)
32
+ node = is_last ? LeafNode : Node
33
+
34
+ case data
35
+ when Hash
36
+ return if @level != -1 && level + 1 > @level
37
+
38
+ data.each do |dir, item|
39
+ dir_node = node.new(dir.to_s, parent_path, prefix, level)
40
+ @nodes << dir_node
41
+ @dirs_count += 1 unless dir_node.root?
42
+
43
+ if level > 0
44
+ postfix = ':pipe'
45
+ postfix = ':space' if is_last
46
+ else
47
+ postfix = ''
48
+ end
49
+
50
+ walk(item, parent_path + dir.to_s,
51
+ prefix + postfix, level + 1, false)
52
+ end
53
+ when Array
54
+ return if @file_limit != -1 && data.size > @file_limit
55
+
56
+ last_data_index = data.size - 1
57
+
58
+ data.each_with_index do |item, i|
59
+ last = (last_data_index == i)
60
+
61
+ walk(item, parent_path, prefix, level, last)
62
+ end
63
+ else
64
+ @nodes << node.new(data.to_s, parent_path, prefix, level)
65
+ @files_count += 1
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require 'pathname'
5
+
6
+ module Lhj
7
+ class Tree
8
+ # A representation of tree node
9
+ #
10
+ # @api private
11
+ class Node
12
+ extend Forwardable
13
+
14
+ # The base name for the directory or file
15
+ attr_reader :name
16
+
17
+ # The parent directory path
18
+ attr_reader :parent
19
+
20
+ # The require path prefix
21
+ attr_reader :prefix
22
+
23
+ # The directory depth
24
+ attr_reader :level
25
+
26
+ # The file stat
27
+ attr_reader :stat
28
+
29
+ # The current path
30
+ attr_reader :path
31
+
32
+ def_delegators :@path, :directory?, :executable?, :file?,
33
+ :symlink?, :socket?, :pipe?
34
+
35
+ def initialize(path, parent, prefix, level)
36
+ if path.is_a? String
37
+ # strip null bytes from the string to avoid throwing errors
38
+ path = path.delete("\0")
39
+ end
40
+
41
+ @path = Pathname.new(path)
42
+ @name = @path.basename
43
+ @parent = Pathname.new(parent)
44
+ @prefix = prefix
45
+ @level = level
46
+ end
47
+
48
+ def full_path
49
+ return parent if name.to_s.empty?
50
+
51
+ parent.join(name)
52
+ end
53
+
54
+ def root?
55
+ parent.to_s.empty?
56
+ end
57
+
58
+ def hidden?
59
+ name.to_s.start_with?('.')
60
+ end
61
+
62
+ def leaf?
63
+ false
64
+ end
65
+
66
+ def to_s
67
+ @name
68
+ end
69
+
70
+ def ==(other)
71
+ other.is_a?(self.class) && other.state_attrs == state_attrs
72
+ end
73
+ alias eql? ==
74
+
75
+ protected
76
+
77
+ def state_attrs
78
+ [@name, @path, @parent, @prefix, @level]
79
+ end
80
+
81
+ ROOT = Node.new('', Pathname.new(''), '', 0).freeze
82
+ end # Node
83
+
84
+ class LeafNode < Node
85
+ def leaf?
86
+ true
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lhj
4
+ class Tree
5
+ # Render nodes as numbered list
6
+ class NumberRenderer
7
+ def initialize(nodes, options = {})
8
+ @indent = options.fetch(:indent, 4)
9
+ @nodes = nodes
10
+ @mark = ' ' * @indent
11
+ end
12
+
13
+ def render
14
+ @nodes.each_with_index.reduce([]) do |acc, (node, i)|
15
+ render_node(acc, node, i, @mark)
16
+ end.join
17
+ end
18
+
19
+ private
20
+
21
+ def render_node(acc, node, i, mark)
22
+ acc << node.prefix.gsub(/:pipe|:space/, mark)
23
+ unless node.root?
24
+ acc << "#{node.level}.#{i} "
25
+ end
26
+ acc << node.name.to_s + "\n"
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pathname'
4
+
5
+ require 'lhj/tree/node'
6
+
7
+ module Lhj
8
+ class Tree
9
+ # Walk and collect nodes from directory.
10
+ #
11
+ # @api public
12
+ class PathWalker
13
+ attr_reader :nodes
14
+
15
+ attr_reader :files_count
16
+
17
+ attr_reader :dirs_count
18
+
19
+ # Create a PathWalker
20
+ #
21
+ # @api public
22
+ def initialize(options = {})
23
+ @files_count = 0
24
+ @dirs_count = 0
25
+ @nodes = []
26
+ @filters = []
27
+ @level = options.fetch(:level) { -1 }
28
+ @file_limit = options.fetch(:file_limit) { - 1 }
29
+
30
+ unless options[:show_hidden]
31
+ add_filter(-> (p) { !p.basename.to_s.start_with?('.') })
32
+ end
33
+
34
+ if options[:only_dirs]
35
+ add_filter(-> (p) { p.directory? })
36
+ end
37
+ end
38
+
39
+ def add_filter(filter)
40
+ @filters << filter
41
+ end
42
+
43
+ # Traverse given path recursively
44
+ #
45
+ # @param [String] path
46
+ # the path to traverse
47
+ #
48
+ # @api public
49
+ def traverse(path)
50
+ root_path = Pathname.new(path)
51
+ empty_path = Pathname.new('')
52
+
53
+ unless root_path.directory?
54
+ raise ArgumentError, "#{root_path} is not a directory path"
55
+ end
56
+
57
+ @nodes << Node.new(root_path, empty_path, '', 0)
58
+
59
+ walk(root_path, root_path.children, '', 1)
60
+ end
61
+
62
+ private
63
+
64
+ # Filter entries
65
+ #
66
+ # @api private
67
+ def filter_entries(entries, filters)
68
+ return entries if filters.nil? || filters.empty?
69
+ filter = filters[0]
70
+ filter_entries(entries.select(&filter), filters[1..-1])
71
+ end
72
+
73
+ # Walk paths recursively
74
+ #
75
+ # @api private
76
+ def walk(parent_path, entries, prefix, level)
77
+ if entries.empty? || (@level != -1 && @level < level)
78
+ return
79
+ else
80
+ return if @file_limit != -1 && entries.size > @file_limit
81
+ processed_paths = filter_entries(entries, @filters).sort
82
+ last_path_index = processed_paths.size - 1
83
+
84
+ processed_paths.each_with_index do |path, i|
85
+ sub_path = path.relative_path_from(parent_path)
86
+
87
+ node = last_path_index == i ? LeafNode : Node
88
+
89
+ if path.directory?
90
+ next if @level != -1 && level + 1 > @level
91
+
92
+ @nodes << node.new(sub_path, parent_path, prefix, level)
93
+ @dirs_count += 1
94
+
95
+ postfix = ':pipe'
96
+ postfix = ':space' if i == last_path_index
97
+
98
+ walk(path, path.children, prefix + postfix, level + 1)
99
+ elsif path.file?
100
+ @nodes << node.new(path, parent_path, prefix, level)
101
+ @files_count += 1
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lhj/tree/node'
4
+ require 'lhj/tree/directory_renderer'
5
+ require 'lhj/tree/number_renderer'
6
+ require 'lhj/tree/hash_walker'
7
+ require 'lhj/tree/path_walker'
8
+
9
+ module Lhj
10
+ class Tree
11
+ # @api public
12
+ def self.[](data)
13
+ new(data)
14
+ end
15
+
16
+ # The list of nodes in this tree.
17
+ attr_reader :nodes
18
+
19
+ # Create a Tree
20
+ #
21
+ # @param [String,Dir,Hash] data
22
+ #
23
+ # @api public
24
+ def initialize(data = nil, options = {}, &block)
25
+ @data = data ? data.dup.freeze : nil
26
+ @walker = select_walker.new(options)
27
+ @nodes = []
28
+
29
+ if @data
30
+ @walker.traverse(data)
31
+ @nodes = @walker.nodes
32
+ end
33
+
34
+ @nodes_stack = []
35
+
36
+ instance_eval(&block) if block_given?
37
+
38
+ freeze
39
+ end
40
+
41
+ # Add node to this tree.
42
+ #
43
+ # @param [Symbol,String] name
44
+ # the name for the node
45
+ #
46
+ # @param [Node, LeafNode] type
47
+ # the type of node to add
48
+ #
49
+ # @example
50
+ # TTY::Tree.new do
51
+ # node '...' do
52
+ # node '...'
53
+ # end
54
+ # end
55
+ #
56
+ # @api public
57
+ def node(name, type = Node, &block)
58
+ parent = @nodes_stack.empty? ? Node::ROOT : @nodes_stack.last
59
+ level = [0, @nodes_stack.size - 1].max
60
+ prefix = ':pipe' * level
61
+ if parent.class == LeafNode
62
+ prefix = ':space' * level
63
+ end
64
+ node = type.new(name, parent.full_path, prefix, @nodes_stack.size)
65
+ @nodes << node
66
+
67
+ return unless block_given?
68
+
69
+ @nodes_stack << node
70
+ if block.arity.zero?
71
+ instance_eval(&block)
72
+ else
73
+ instance_eval(&(->(*_args) { block[node] }))
74
+ end
75
+ @nodes_stack.pop
76
+ end
77
+
78
+ # Add leaf node
79
+ #
80
+ # @api public
81
+ def leaf(name, &block)
82
+ node(name, LeafNode, &block)
83
+ end
84
+
85
+ # @api public
86
+ def render(options = {})
87
+ as = options.delete(:as) || :dir
88
+ renderer = select_renderer(as).new(nodes, options)
89
+ renderer.render
90
+ end
91
+
92
+ private
93
+
94
+ # @api private
95
+ def select_walker
96
+ if @data.is_a?(Hash) || @data.nil?
97
+ HashWalker
98
+ else
99
+ @data ||= Dir.pwd
100
+ PathWalker
101
+ end
102
+ end
103
+
104
+ def select_renderer(as)
105
+ case as
106
+ when :dir, :directory then DirectoryRenderer
107
+ when :num, :number then NumberRenderer
108
+ end
109
+ end
110
+ end
111
+ end
112
+