abak-flow 0.3.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MGU3ZjFmYjE3OWMyMDM4NTI1NWJjYzQxZDFjZTM5YmQ2YmQ0M2Q1ZQ==
5
+ data.tar.gz: !binary |-
6
+ NjViMDJhOWE1ZmRhMTU0ZjZkNjVkNjhlYTBiZmE0ZTM1NjgyYzlkZA==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NWE0M2ZjYmJkMDQ0MWU4OWUxZDBiODk4NTU0N2Q2M2IyZTU4ZGIyZTgxZTBl
10
+ NGEyY2M4YTZjMjI4ZmZjY2FlZjJjMTZiMzg0YThmYTBkN2E1ODA2NzVjYjc2
11
+ MjFiZDlkZDdiMmU1ODExNzJiNzBhYzA0MDE1ZWNjMTIxMjViOWI=
12
+ data.tar.gz: !binary |-
13
+ MzZkYmQ0OThkMDcxYjFlNmI4MTdlYmRjOTY1NzBmNDYxNTI3Mjc5M2M5ZjVh
14
+ YmM2ZDJlM2ZhOTk0YjQ5MWJkZmVkNmVkY2I2MmMwOTYxMTQyOWZhOTBiMGEw
15
+ YzVmYjYzNjY4ZDZiOGZmYjEyMzFkOTM4MGFhYjI1YjgwZTQ1ZGU=
data/.gitignore CHANGED
@@ -1,8 +1,11 @@
1
1
  *.gem
2
+ .ruby-*
2
3
  .bundle
3
4
  Gemfile.lock
4
5
  pkg/*
5
6
  tmp/
6
7
  .idea/
8
+ coverage/
7
9
  .rvmrc
8
10
  .DS_Store
11
+ tmtags*
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ branches:
5
+ only:
6
+ - release-1.0
7
+ bundler_args: --without linux mac
data/Gemfile CHANGED
@@ -1,3 +1,12 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- gemspec
3
+ gemspec
4
+
5
+ group :linux do
6
+ gem "libnotify"
7
+ gem "rb-inotify"
8
+ end
9
+
10
+ group :mac do
11
+ gem "terminal-notifier-guard"
12
+ end
data/README.md CHANGED
@@ -2,7 +2,9 @@ Abak-flow
2
2
  =========
3
3
  Нет, это не новая идеология ведения проекта, это всего лишь набор утилит которые помогают связать использование [git-flow](https://github.com/nvie/gitflow) и [github flow](http://scottchacon.com/2011/08/31/github-flow.html)
4
4
 
5
- **Начиная с версии v0.2.1 используется авторизация OAuth2. [Как ей пользоваться](https://github.com/Strech/abak-flow/wiki/How-start-work-with-new-abak-flow)**
5
+ **Начиная с версии v0.2.1 используется авторизация OAuth2. [Как ей пользоваться?](https://github.com/Strech/abak-flow/wiki/How-start-work-with-new-abak-flow)**
6
+
7
+ **Начиная с версии v1.0.0 используется новый формат конфигурации. [Как мигрировать старую?](https://github.com/Strech/abak-flow/wiki/How-start-work-with-abak-flow-v1.0.0)**
6
8
 
7
9
  # Концепция
8
10
  Идеология git-flow использует следующий набор веток:
@@ -25,10 +27,10 @@ Github-flow же наоборот ведет основную разработк
25
27
 
26
28
  # Установка
27
29
 
28
- $ gem install abak-flow
30
+ $ gem install abak-flow -v 1.0.0
29
31
  $ git config --global alias.request '!request'
30
- $ git config --global abak.apiuser YOUR_GITHUB_MAIL@gmail.com
31
- $ git config --global abak.apitoken 0123456789YOUR_GITHUB_API_TOKEN
32
+ $ git config --global abak-flow.oauth-user YOUR_GITHUB_MAIL@gmail.com
33
+ $ git config --global abak-flow.oauth-token 0123456789YOUR_GITHUB_API_TOKEN
32
34
  $ git remote add upstream git://github.com/GITHUB_PROJECT_USER/GITHUB_PROJECT_NAME.git
33
35
 
34
36
  ### А если я использую прокси, как быть?
@@ -40,13 +42,13 @@ Github-flow же наоборот ведет основную разработк
40
42
 
41
43
  ---
42
44
 
43
- **Заметьте:** В конфиге git, значением *abak.apiuser* должен являться тот email адрес, под которым вы заходите на github
45
+ **Заметьте:** В конфиге git, значением *abak.oauth-user* должен являться тот email адрес, под которым вы заходите на github
44
46
 
45
47
  **Обратите внимание:** В данном контексте под **upstream** подразумевается адрес репозитория в который будут оформляться pull request. А репозиторием **origin** будет являться ваш форк
46
48
 
47
49
  # С чего начать?
48
50
 
49
- $ git request readycheck
51
+ $ git request checkup
50
52
 
51
53
  или
52
54
 
@@ -58,7 +60,7 @@ Github-flow же наоборот ведет основную разработк
58
60
  ### Самый простой способ начать новую задачу:
59
61
 
60
62
  $ git checkout develop
61
- $ git request feature 'TASK-001'
63
+ $ git flow feature start 'TASK-001'
62
64
  $ touch 'hello.txt' && echo 'Hello world!' > hello.txt
63
65
  $ git commit -a -m 'Hello world commit'
64
66
  $ git request publish
@@ -68,7 +70,7 @@ Github-flow же наоборот ведет основную разработк
68
70
  Теперь то же самое, только словами:
69
71
 
70
72
  * Переключимся в ветку develop
71
- * Abak-flow создаст ветку, пригодную для оформления pull request (правила именования и правила самого реквеста)
73
+ * git-flow создаст ветку, пригодную для оформления pull request (правила именования и правила самого реквеста)
72
74
  * Простое создание нового файла
73
75
  * Git процедуры добавления своих изменений в репозиторий
74
76
  * Затем публикация вашей ветки на вашем форке (если таковая уже есть, то просто обновление), затем оформление pull request из этой ветки в соответствующую правилам ветку на upstream (в данном случае это будет ветка develop)
@@ -76,36 +78,17 @@ Github-flow же наоборот ведет основную разработк
76
78
  Для задач, которые должны быть выполнены в виде hotfix принцип тот же:
77
79
 
78
80
  $ git checkout master
79
- $ git request hotfix 'TASK-001'
81
+ $ git flow hotfix start 'TASK-001'
80
82
  $ …
81
83
  $ git request publish
82
84
 
83
85
  *На самом деле переключаться на master или develop в самом начале вовсе не обязательно, этот шаг был приведен для пущей ясности*
84
86
 
85
- ### Обновление ветки на удаленном репозитории:
86
-
87
- $ git checkout feature/TASK-001
88
- $ git request update
89
-
90
- ### Завершение текущей задачи:
91
- Вообще, завершать задачу лучше только после того, как ваш pull request был принят. Почему? На самом деле по ряду причин. По умолчанию эта команда удаляет как вашу текущую ветку с задачей в локальном репозитории и в добавок ко всему - на вашем удаленном репозитории (форке)
92
-
93
- $ git checkout feature/TASK-001
94
- $ git request done
95
-
96
- Чтобы оставить какую либо ветку в живых возможно напрямую указать, какую копию ветки **удалить**, локальную или же удаленную (на origin)
97
-
98
- $ git checkout feature/TASK-001
99
- $ git request done --origin
100
-
101
- Или же так
102
-
103
- $ git checkout feature/TASK-001
104
- $ git request done --local
105
-
106
87
  ## Маленькие хитрости
107
88
  Если сразу правильно именовать ветки, т.е ветку с задачей создавать с именем, такого формата TASK-001, то, в описание pull request автоматически вставится ссылка на задачу в jira, а в имя pull request сразу вставится название, состоящее из имени задачи, т.е TASK-001
108
89
 
90
+ Если делать реквест из ветки не соответствующей формату TASK-001, то в название подставится последний commit message. Если вы считаете, что нужно указать, что-то другое - всегда можно воспользоваться опцией `--title`
91
+
109
92
  ## А помощь?
110
93
  Многие команды имеют какие-то дополнительные опции. Но они нужны только в экзотических случаях. Но при любом раскладе подсказку и тонкий намек всегда можно получить воспользовавших такой командой:
111
94
 
data/Rakefile CHANGED
@@ -1 +1,26 @@
1
1
  require "bundler/gem_tasks"
2
+
3
+ require "yard"
4
+ require "yard-tomdoc"
5
+ require "cane/rake_task"
6
+ require "rspec/core/rake_task"
7
+
8
+ desc "Ready check"
9
+ task default: [:quality, :coverage, :doc]
10
+
11
+ RSpec::Core::RakeTask.new(:coverage) do |rspec|
12
+ ENV["COVERAGE"] = "true"
13
+ end
14
+
15
+ Cane::RakeTask.new(:quality) do |cane|
16
+ cane.abc_max = 15
17
+ cane.abc_glob = cane.style_glob = cane.doc_glob = "{lib}/abak-flow/*.rb"
18
+ cane.style_exclude = %w({lib}/abak-flow/request.rb)
19
+ cane.style_measure = 120
20
+ cane.parallel = false
21
+ end
22
+
23
+ YARD::Rake::YardocTask.new(:doc) do |yard|
24
+ yard.files = %w({apps,models,lib}/**/*.rb)
25
+ yard.options = %w(--embed-mixins --protected --plugin tomdoc)
26
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.2
1
+ 1.0
data/abak-flow.gemspec CHANGED
@@ -1,24 +1,28 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path('../lib', __FILE__)
3
- require 'abak-flow/version'
1
+ # coding: utf-8
2
+ $:.push File.expand_path("../lib", __FILE__)
4
3
 
5
- Gem::Specification.new do |s|
6
- s.name = 'abak-flow'
7
- s.version = Abak::Flow::VERSION
8
- s.authors = ['Strech (aka Sergey Fedorov)']
9
- s.email = ['oni.strech@gmail.com']
10
- s.homepage = 'https://github.com/Strech/abak-flow'
11
- s.summary = %q{Совмещение 2-х подходов разработки Git-flow & Github-flow}
12
- s.description = %q{Простой набор правил и комманд, заточеных для работы в git-flow с использование в качестве удаленного репозитория github}
4
+ require "abak-flow/version"
13
5
 
14
- s.rubyforge_project = 'abak-flow'
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "abak-flow"
8
+ gem.version = Abak::Flow::VERSION
9
+ gem.authors = ["Strech (aka Sergey Fedorov)"]
10
+ gem.email = ["oni.strech@gmail.com"]
11
+ gem.homepage = "https://github.com/Strech/abak-flow"
12
+ gem.summary = "Совмещение 2-х подходов разработки Git-flow & Github-flow"
13
+ gem.description = "Простой набор правил и комманд, заточеных для работы в git-flow с использование в качестве удаленного репозитория github"
15
14
 
16
- s.files = `git ls-files`.split("\n")
17
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
- s.require_paths = ['lib']
15
+ gem.rubyforge_project = "abak-flow"
20
16
 
21
- s.add_runtime_dependency 'hub', '~> 1.10.3'
22
- s.add_runtime_dependency 'commander', '~> 4.1.2'
23
- s.add_runtime_dependency 'octokit', '~> 1.19.0'
17
+ gem.files = `git ls-files`.split("\n")
18
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ gem.require_paths = ["lib"]
21
+
22
+ gem.add_runtime_dependency "octokit", "~> 1.19.0"
23
+ gem.add_runtime_dependency "git", "~> 1.2.5"
24
+ gem.add_runtime_dependency "commander", ">= 4.1.3"
25
+ gem.add_runtime_dependency "ruler", ">= 1.4.2"
26
+ gem.add_runtime_dependency "i18n", ">= 0.6.1"
27
+ gem.add_runtime_dependency "ansi", ">= 1.4.3"
24
28
  end
data/bin/request CHANGED
@@ -1,4 +1,3 @@
1
1
  #!/usr/bin/env ruby
2
- # -*- encoding: utf-8 -*-
2
+ # coding: utf-8
3
3
  require 'abak-flow'
4
- require "abak-flow/request"
@@ -0,0 +1,108 @@
1
+ # coding: utf-8
2
+
3
+ module Abak::Flow
4
+ class Branch
5
+ FOLDER_HOTFIX = "hotfix".freeze
6
+ FOLDER_FEATURE = "feature".freeze
7
+ TASK_FORMAT = /^\w+\-\d{1,}$/.freeze
8
+
9
+ DEVELOPMENT = "develop".freeze
10
+ MASTER = "master".freeze
11
+
12
+ MAPPING = {
13
+ FOLDER_HOTFIX => MASTER,
14
+ FOLDER_FEATURE => DEVELOPMENT
15
+ }.freeze
16
+
17
+ def initialize(branch, manager)
18
+ @manager = manager
19
+ @branch = branch.is_a?(Git::Branch) ? branch
20
+ : manager.git.branch(branch)
21
+ end
22
+
23
+ def name
24
+ @branch.full
25
+ end
26
+
27
+ def message
28
+ @branch.gcommit.message
29
+ end
30
+
31
+ def folder
32
+ split_prefix_and_task.first
33
+ end
34
+
35
+ def task
36
+ split_prefix_and_task.last
37
+ end
38
+
39
+ def compare_link(branch)
40
+ diff = "#{@manager.repository.upstream.owner}:#{branch}...#{@branch}"
41
+
42
+ File.join [
43
+ @manager.github.web_endpoint,
44
+ @manager.repository.origin.to_s,
45
+ "compare", diff
46
+ ]
47
+ end
48
+
49
+ def update
50
+ origin = @manager.repository.origin.repo
51
+ @manager.git.push(origin, @branch)
52
+ end
53
+
54
+ def pick_up_base_name
55
+ mappable? ? MAPPING[folder]
56
+ : name
57
+ end
58
+
59
+ def pick_up_title
60
+ tracker_task? ? task
61
+ : message
62
+ end
63
+
64
+ # TODO : Вынести в i18n
65
+ def pick_up_body
66
+ tracker_task? ? "http://jira.railsc.ru/browse/#{task}"
67
+ : nil
68
+ end
69
+
70
+ def hotfix?
71
+ folder == FOLDER_HOTFIX
72
+ end
73
+
74
+ def feature?
75
+ folder == FOLDER_FEATURE
76
+ end
77
+
78
+ def tracker_task?
79
+ !(task =~ TASK_FORMAT).nil?
80
+ end
81
+
82
+ def mappable?
83
+ hotfix? || feature?
84
+ end
85
+
86
+ def current?
87
+ @branch.current
88
+ end
89
+
90
+ def valid?
91
+ !@branch.name.empty?
92
+ end
93
+
94
+ def to_s
95
+ @branch.to_s
96
+ end
97
+
98
+ private
99
+ def split_prefix_and_task
100
+ return @folder_and_task if defined? @folder_and_task
101
+
102
+ matches = name.match(/^(?<prefix>.+)\/(?<task>.+)$/)
103
+
104
+ @folder_and_task = matches.nil? ? [nil, nil]
105
+ : [matches[:prefix], matches[:task]]
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,68 @@
1
+ # coding: utf-8
2
+ #
3
+ # Wrapper class for git branches.
4
+ # Provides access to git branches and also defines current_branch
5
+ module Abak::Flow
6
+ module Branches
7
+ extend Forwardable
8
+
9
+ def_delegator "Abak::Flow::Git.instance", :git
10
+
11
+ def self.current_branch
12
+ Branch.new git.branches[git.current_branch]
13
+ end
14
+
15
+ # ==========================================================================
16
+ # TODO : Refactor
17
+ # 3. Statistics & Cleaning
18
+ #
19
+ # => PullRequest.garbage
20
+ # => PullRequest.clean
21
+ # => PullRequest.clean(hard: true)
22
+ def self.garbage
23
+ Project.init
24
+ [Project.upstream.repo, Project.origin.repo].map(&:fetch)
25
+
26
+ branches = GithubClient.connection.branches(Project.origin.to_s)
27
+ .reject { |branch| %w(master develop).include? branch.name }
28
+
29
+ messages = Messages.new "pull_request.garbage"
30
+ messages << [:collected_branches, {count: branches.count}]
31
+
32
+ branches.each_with_index do |branch, index|
33
+
34
+ # WRONG PREFIX
35
+ upstream_branch = Git.command_lines("branch", ["-r", "--contain", branch.commit.sha])
36
+ .select { |branches| branches.include? "upstream/#{branch.prefix}" }
37
+
38
+ local_sha = git.branches[branch.name] ? git.branches[branch.name].gcommit.sha : ""
39
+
40
+ statuses = {
41
+ branch_unused: upstream_branch.empty?,
42
+ branch_differ: !local_sha.empty? && local_sha != branch.commit.sha,
43
+ branch_missing: local_sha.empty?
44
+ }
45
+
46
+ unless statuses.values.inject &:|
47
+ messages << [:deletion_allowed, {index: index, branch_name: branch.name}]
48
+ next
49
+ end
50
+
51
+ diagnoses = statuses.select { |_, bool| bool }.
52
+ map { |name, _| messages.t name }.
53
+ map { |msg| " ↪ #{msg}" }.
54
+ join("\n")
55
+
56
+ if statuses.select { |_, bool| bool }.keys == [:missing]
57
+ messages << [:deletion_possibly, {index: index, branch_name: branch.name, diagnoses: diagnoses}]
58
+ else
59
+ messages << [:deletion_restricted, {index: index, branch_name: branch.name, diagnoses: diagnoses}]
60
+ end
61
+ end
62
+
63
+ messages
64
+ end
65
+
66
+
67
+ end
68
+ end
@@ -0,0 +1,67 @@
1
+ # coding: utf-8
2
+ require "i18n"
3
+ require "ruler"
4
+
5
+ module Abak::Flow
6
+ class Configuration
7
+ include Ruler
8
+
9
+ OPTIONS = [:oauth_user, :oauth_token, :locale, :http_proxy].freeze
10
+ LOCALE_FILES = File.join(File.dirname(__FILE__), "locales/*.{rb,yml}").freeze
11
+
12
+ attr_reader :errors
13
+
14
+ def initialize(manager)
15
+ @manager = manager
16
+ @errors = []
17
+
18
+ configure!
19
+ end
20
+
21
+ def ready?
22
+ @errors = []
23
+
24
+ multi_ruleset do
25
+ fact(:oauth_user_not_setup) { oauth_user.nil? }
26
+ fact(:oauth_token_not_setup) { oauth_token.nil? }
27
+
28
+ rule([:oauth_user_not_setup]) { @errors << I18n.t("configuration.errors.oauth_user_not_setup") }
29
+ rule([:oauth_token_not_setup]) { @errors << I18n.t("configuration.errors.oauth_token_not_setup") }
30
+ end
31
+
32
+ @errors.empty? ? true : false
33
+ end
34
+
35
+ def display_name
36
+ I18n.t("configuration.name")
37
+ end
38
+
39
+ private
40
+ def configure!
41
+ load_gitconfig
42
+ setup_locale
43
+ end
44
+
45
+ def setup_locale
46
+ I18n.load_path += Dir.glob(LOCALE_FILES)
47
+ I18n.locale = locale
48
+ end
49
+
50
+ def load_gitconfig
51
+ git_config = @manager.git.config.select { |k, _| k.include? "abak-flow." }
52
+ .map { |k,v| [to_method_name(k), v] }
53
+
54
+ config = Hash[git_config]
55
+ config[:locale] ||= "en"
56
+ config[:http_proxy] ||= ENV["http_proxy"] || ENV["HTTP_PROXY"]
57
+
58
+ OPTIONS.each do |name|
59
+ define_singleton_method(name) { config[name] }
60
+ end
61
+ end
62
+
63
+ def to_method_name(name)
64
+ name.sub(/abak-flow./, "").gsub(/\W/, "_").to_sym
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,32 @@
1
+ en:
2
+ configuration:
3
+ name: Configuration
4
+ errors:
5
+ oauth_user_not_setup: Options oauth_user not setted
6
+ oauth_token_not_setup: Options oauth_token not setted
7
+ recommendations: "Check [abak-flow] section in ~/.gitcofig file"
8
+
9
+ repository:
10
+ name: Repository
11
+ errors:
12
+ origin_not_setup: Repository with name 'origin' not found
13
+ upstream_not_setup: Repository with name 'upstream' not found
14
+ recommendations: "Check .git/cofig file"
15
+
16
+ pull_request:
17
+ name: Pull Request
18
+
19
+ commands:
20
+ checkup:
21
+ fail: You are not prepared!
22
+ success: "Congratulations, you are ready to ROCK :)"
23
+ compare:
24
+ fail: Something goes wrong!
25
+ updating: "Updating %{branch} → %{upstream}"
26
+ diverging: "Branches may diverging\nAdvice: switch to branch '%{branch}' and retry operation"
27
+ publish:
28
+ fail: Something goes wrong!
29
+ success: "Pull request successfuly created %{link}"
30
+ requesting: "Creating pull request %{branch} → %{upstream}"
31
+ updating: "Updating %{branch} → %{upstream}"
32
+ nothing: I have nothing to say ...
@@ -0,0 +1,32 @@
1
+ ru:
2
+ configuration:
3
+ name: Корфигурация
4
+ errors:
5
+ oauth_user_not_setup: Не установлена опция oauth_user
6
+ oauth_token_not_setup: Не установлена опция oauth_token
7
+ recommendations: "Проверьте секцию [abak-flow] в файле ~/.gitcofig"
8
+
9
+ repository:
10
+ name: Репозиторий
11
+ errors:
12
+ origin_not_setup: Репозиторий с именем 'origin' не найден
13
+ upstream_not_setup: Репозиторий с именем 'upstream' не найден
14
+ recommendations: Проверьте файл .git/cofig
15
+
16
+ pull_request:
17
+ name: Пулл реквест
18
+
19
+ commands:
20
+ checkup:
21
+ fail: "Вы не готовы!"
22
+ success: "Поздравляем, вы готовы чтобы жечь :)"
23
+ compare:
24
+ fail: Что-то пошло не так!
25
+ updating: "Обновление %{branch} → %{upstream}"
26
+ diverging: "Ветки могут расходиться.\nСовет: переключитесь в ветку '%{branch}' и повторите операцию"
27
+ publish:
28
+ fail: Что-то пошло не так!
29
+ success: "Пулл реквест успешно создан %{link}"
30
+ requesting: "Создание пулл реквеста %{branch} → %{upstream}"
31
+ updating: "Обновление %{branch} → %{upstream}"
32
+ nothing: Мне нечего добавить ...
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ require "git"
3
+ require "octokit"
4
+
5
+ module Abak::Flow
6
+ class Manager
7
+
8
+ def initialize
9
+ # preload dependencies
10
+ configuration
11
+ repository
12
+
13
+ yield self if block_given?
14
+ end
15
+
16
+ def configuration
17
+ @configuration ||= Configuration.new(self)
18
+ end
19
+
20
+ def repository
21
+ @repository ||= Repository.new(self)
22
+ end
23
+
24
+ def github
25
+ @github ||= Octokit::Client.new(login: configuration.oauth_user,
26
+ oauth_token: configuration.oauth_token,
27
+ proxy: configuration.http_proxy)
28
+ end
29
+
30
+ def git
31
+ @git ||= Git.open(".")
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,86 @@
1
+ # coding : utf-8
2
+ require "i18n"
3
+
4
+ # TODO : Нужен простой метод, для перевода без скоупа
5
+ module Abak::Flow
6
+ class Messages
7
+ extend Forwardable
8
+
9
+ attr_reader :scope, :elements
10
+
11
+ def initialize(scope)
12
+ Configuration.instance
13
+
14
+ @scope = scope
15
+ @elements = []
16
+ end
17
+
18
+ # Iterate elements from locale scope (translating online)
19
+ #
20
+ # Returns nothing
21
+ def each
22
+ raise ArgumentError, "No block given" unless block_given?
23
+
24
+ elements.each do |key|
25
+ yield translate(key)
26
+ end
27
+ end
28
+
29
+ # Put item to elements
30
+ #
31
+ # Returns Symbol
32
+ def push(element)
33
+ @elements << element
34
+ end
35
+ alias :<< :push
36
+
37
+ # section header from locale scope
38
+ #
39
+ # Returns String
40
+ def header
41
+ translate :header
42
+ end
43
+
44
+ # Print all elements from locale scope without header
45
+ #
46
+ # Returns Symbol
47
+ def to_s
48
+ return "" if elements.empty?
49
+
50
+ elements.collect { |element| translate *element } * "\n"
51
+ end
52
+
53
+ def print
54
+ return "" if elements.empty?
55
+
56
+ all_elements = []
57
+ elements.each_with_index do |element, index|
58
+ all_elements << "#{index + 1}. #{translate(*element)}"
59
+ end
60
+
61
+ all_elements * "\n"
62
+ end
63
+
64
+ # Print section header from locale scope and all elements from scope
65
+ #
66
+ # Returns String
67
+ def pretty_print
68
+ return "" if elements.empty?
69
+
70
+ [header, print] * "\n\n"
71
+ end
72
+ alias :pp :pretty_print
73
+
74
+ def translate(key, options = {})
75
+ I18n.t key, {scope: scope}.merge!(options)
76
+ end
77
+ alias :t :translate
78
+
79
+ def purge!
80
+ @elements = []
81
+ end
82
+
83
+ private
84
+ def_delegator :elements, :empty?
85
+ end
86
+ end