gemspec-bump 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b7ce027c8b2fd74a6067ab35b09c98964ae30def
4
+ data.tar.gz: e814323485ac6a4bcdd3c031d5e3d4e1842ebd68
5
+ SHA512:
6
+ metadata.gz: 69d1b03dc35f2f5a86147e34ce1fa6dd1317374799e35a7819a90ee4ed404e358d60e01075373e9e98db404fb74d6ce0525915be65e8ab5f5d222aa5d9147490
7
+ data.tar.gz: 43a143909720f7d725a59c336145512a69d47080fedad6f5dec13a827db971385cbcbd0f937b58bc1bfa3686f7a835bd36bbf3651956426de283fc49e70fc358
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ /pkg/
2
+ /Gemfile.lock
3
+ /LICENSES
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gemspec.gemspec
4
+ gem 'gemspec', '~> 0.2'
5
+ gemspec glob: '*.gemspec'
@@ -0,0 +1,29 @@
1
+ #Usage: gemspec-version VERSION VERSION_DIFF
2
+
3
+ gemspec-version combines a VERSION string with a VERSION_DIFF string.
4
+ A version is a series of integers seperated by dots.
5
+ A versiondiff is a series of integers, optionaly prepended by the + or - sign.
6
+
7
+ Each VERSION integer is combined with its corresponding VERSION_DIFF integer in the following
8
+ fashion:
9
+
10
+ - An unsigned integer overwrites the VERSION integer.
11
+ - A signed integer (+ or -) is added to the VERSION integer.
12
+ - The righter-most VERSION_DIFF integer combines with the righter-most VERSION integer
13
+
14
+ ##Examples:
15
+ #Bump the third digit by 1
16
+ gemspec-version 1.1.1 +1
17
+ => 1.1.2
18
+
19
+ #Bump the second digit by 1, zeroing the third
20
+ gemspec-version 1.1.1 +1.0
21
+ => 1.1.2
22
+
23
+ #Set the first digit to 5, bump the second by one, and set the last one to 0
24
+ gemspec-version 1.0.1 5.+1.0
25
+ => 5.1.0
26
+
27
+ #Bump the second digit by 3; set the last one to 4
28
+ gemspec-version 1.1.1 +3.4
29
+ => 1.4.4
data/README.md ADDED
@@ -0,0 +1,25 @@
1
+ #gemspec-bump
2
+
3
+ A library for combining `Version`s with `VersionDiff`s into new `Version`s.
4
+
5
+ ##Basic
6
+
7
+ The basic functionality is exposed in the CLI via the `versionpatch` and `versionpatch-file` executables.
8
+ See README-VERSIONPATCH.md for how to use `versionpatch`.
9
+
10
+ See the specs or read the code for in-ruby examples of the basic functionality.
11
+
12
+ ## gemspec-bump
13
+ `gemspec-bump` it assumes you’re in a git repo that has the VERSION and VERSION_FOR_HUMANS files in its root, of which each contains a version string, and that you’re on a non-master branch (
14
+ e.g. a release branch or your develop branch if you’re using git flow).
15
+
16
+ The executable gets a new version for at least the VERSION version by either opening the VERSION file in your text editor (if no argument is given) or by applying arguments as VersionDiffs to VERSION and VERSION_FOR_HUMANS respectively
17
+ (the latter is optional). It writes the new version(s), creates a commit, merges it with master, tags the master merge commit appropriately, merges the merge commit back to the original branch, and
18
+ outputs a reverse, decorated, one-line commit log so that you can see where you’re at.
19
+
20
+ If you’re on a branch based on master, this whole chain should succeed without any need for additional user input.
21
+
22
+ See `gemspec-bump --help` for more information.
23
+
24
+ ## What’s it got to do with gemspecs
25
+ Nothing. This was made to be used in conjuction with my `gemspec` gem so why not use its namespace.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ task :default => :test
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ lib/gemspec/bump/VERSION
data/VERSIONING.md ADDED
@@ -0,0 +1,18 @@
1
+ ## Versioning
2
+ ### Version Number for Machines
3
+
4
+ This gem uses a slightly modified version of the **SemVer** specification, namely:
5
+ ```ruby
6
+ spec.version = "BREAKING.PATCHES.NONBREAKING"
7
+ ```
8
+ You can use this versioning with your dependency tools, only you have a somewhat stronger guarantee that your
9
+ code won't break if you limit yourself to the third number, but you need to allow second level updates in order to
10
+ get (security and other) patches.
11
+
12
+ ### Version Number for Humans
13
+ Since the above-described type of versioning doesn't tell you anything about the functional state of the gem (you can go from a "hello world" to a full blown operating system
14
+ without making a breaking change, as long as your operating system prints "hello world" to the screen) (SemVer, when used correctly, doesn't tell anything about the functional state of a software package either), a second, human-friendly version number can be found in `spec.metadata[:human_version]`.
15
+
16
+ The magnitude of this version number shall be made to correspond to actual functional changes in the software. If I've worked a lot on the package, I'll make it move a lot, but unless I've made breaking changes, I'll stick to only moving the third number in the `spec.version` version.
17
+
18
+ This number is for you. If you see it increase a lot, it probably means much more new goodies, but is less strictly defined then the version number for the machine. (I reserve the right to later change the way I change this number).
@@ -0,0 +1 @@
1
+ lib/gemspec/bump/VERSION_FOR_HUMANS
data/bin/gemspec-bump ADDED
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ require 'shellwords'
4
+
5
+ def usage
6
+ <<-EOF.gsub(/^ /,'')
7
+ Usage: gemspec-bump [VERSION-diff [VERSION_FOR_HUMANS-diff]]
8
+
9
+ Apply given diffs to VERSION and VERSION_FOR_HUMANS respectively where VERSION and VERSION_FOR_HUMANS are files (possibly symlinks) in the root of the git repo, which should
10
+ contain version strings (integers seperated by dots) and be managed by git.
11
+
12
+ At least VERSION-diff must be present. If it is not, $EDITOR is open for both.
13
+
14
+ If at the end VERSION differs from what it is at the top of the current branch,
15
+ the VERSION file will be committed with a generated message.
16
+ This commit will be merged into master and, if the merge is sucessful, the top of master will be
17
+ tagged `v$(cat VERSION)` and `h$(cat VERSION_FOR_HUMANS)` and merged back into the previous branch.
18
+ EOF
19
+ end
20
+
21
+ require 'gemspec/git'
22
+ require 'gemspec/bump'
23
+ include Gemspec
24
+ Git.cdroot!
25
+ $? == 0 or (
26
+ warn "Not in a git repository"
27
+ exit 1
28
+ )
29
+
30
+ if (original_branch=`git branch`.split("\n").grep(/^\*/)[0].sub(/^\*\s*/,'')) == 'master'
31
+ warn "Bumping must be done on a non-master branch.\n If succesful, the result will be merged into master and back to the original branch"
32
+ end
33
+
34
+ new_version = nil
35
+ new_version_for_humans = nil
36
+
37
+ if ARGV[0]
38
+ old_version = File.read('VERSION').chomp
39
+ new_version = Version.new(old_version).apply(VersionDiff.new(ARGV[0])).to_s
40
+ File.write('VERSION', new_version + "\n")
41
+
42
+ if ARGV[1]
43
+ old_version_for_humans = File.read('VERSION_FOR_HUMANS').chomp
44
+ new_version_for_humans = Version.new(old_version_for_humans).apply(VersionDiff.new(ARGV[1])).to_s
45
+ File.write('VERSION_FOR_HUMANS', new_version_for_humans + "\n")
46
+ end
47
+ else
48
+ system(ENV['EDITOR'], 'VERSION', 'VERSION_FOR_HUMANS')
49
+ end
50
+
51
+ if `git status --porcelain "$(readlink VERSION)"`.chomp == ""
52
+ system(ENV['EDITOR'], 'VERSION')
53
+ end
54
+
55
+ if `git status --porcelain "$(readlink VERSION)"`.chomp == ""
56
+ warn "A bump must change VERSION"
57
+ exit 1
58
+ end
59
+
60
+ new_version = File.read('VERSION').chomp
61
+ new_version_for_humans = File.read('VERSION_FOR_HUMANS').chomp
62
+
63
+ files_to_git_add = %w[VERSION VERSION_FOR_HUMANS].map! {|f| File.symlink?(f) ? File.readlink(f) : f }
64
+ system('git', 'add','--', *files_to_git_add)
65
+
66
+ msg = "Bump to VERSION to v#{new_version}\n\nVERSION_FOR_HUMANS == #{new_version_for_humans}"
67
+ system <<-EOF
68
+ set -e
69
+ git commit -m #{Shellwords.escape msg}
70
+ git checkout master
71
+ git merge @{-1} --no-edit --no-ff
72
+ git tag v#{Shellwords.escape new_version}
73
+ git tag h#{Shellwords.escape new_version_for_humans} || true
74
+ git checkout @{-1}
75
+ git merge master
76
+ git log --oneline --decorate | tac
77
+ EOF
data/bin/versionpatch ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ require 'gemspec/bump'
5
+ include Gemspec
6
+
7
+ def usage
8
+ File.read(File.expand_path('../../README-VERSIONPATCH.md', __FILE__))
9
+ end
10
+
11
+ if ARGV.delete('-h') || ARGV.delete('--help')
12
+ puts usage
13
+ exit
14
+ end
15
+
16
+ ARGV.size == 2 or (
17
+ warn usage
18
+ exit 1
19
+ )
20
+ puts Version.new(ARGV.first).apply(VersionDiff.new(ARGV.last))
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ require 'gemspec/version'
5
+ include Gemspec
6
+
7
+ def usage
8
+ <<-EOF.gsub(/^ /,'')
9
+ Usage: versionpatch-file VERSIONFILE VERSIONDIFF
10
+
11
+ Works the same as versionpatch expect the VERSION string is read from VERSIONFILE and the
12
+ result is also written to VERSIONFILE.
13
+
14
+ See `versionpatch --help` for more information.
15
+ EOF
16
+ end
17
+
18
+ if ARGV.delete('-h') || ARGV.delete('--help')
19
+ puts usage
20
+ exit
21
+ end
22
+
23
+ ARGV.size == 1 or (
24
+ warn usage
25
+ exit 1
26
+ )
27
+ old_version = File.read(ARGV.first)
28
+ new_version = Version.new(ARGV[0]).apply(VersionDiff.new(ARGV[1]))
29
+ File.write(ARGV[0], new_version)
data/gemspec.gemspec ADDED
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+
3
+ #Naming utils, git utils, and default boilerplate
4
+ require 'gemspec'
5
+
6
+ #This is a place to put custom overrides to Gemspec.boilerplate
7
+ begin; require_relative 'gemspec.rb'; rescue LoadError; end
8
+
9
+ Gem::Specification.new do |s|
10
+
11
+ #Name is the name of the project root directory
12
+ s.name = Gemspec.base_dirname(__FILE__)
13
+
14
+ Gemspec.boilerplate(s)
15
+
16
+ #s.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com' to prevent pushes to rubygems.org, or delete to allow pushes to any server."
17
+
18
+ #####Must change
19
+ s.summary = %q{A version bumper}
20
+ s.description = %q{A flexible and concise version bumper that can, in a single command, take care of all the git ceremony in a git-flow compatible fashion . }
21
+ s.licenses = %w[GPL-2.0]
22
+
23
+
24
+ #####Unlikely to change
25
+ s.email = [ `git config user.email`.chomp ]
26
+ s.homepage = "https://github.com/#{`git config github.username`.chomp}/#{s.name}.git"
27
+ $? == 0 or s.homepage = nil
28
+ ###################################
29
+
30
+ #Dependencies
31
+ s.add_dependency 'gemspec', '~> 0'
32
+ s.add_development_dependency 'rake', '~> 10.4'
33
+ s.add_development_dependency 'minitest-documentation'
34
+
35
+ end
@@ -0,0 +1,49 @@
1
+ require "gemspec/bump/version"
2
+
3
+ module Gemspec
4
+ class Version
5
+ IllegalFormat = Class.new(ArgumentError)
6
+
7
+ attr_accessor :data
8
+
9
+ def initialize(string_or_array)
10
+ @data = string_or_array
11
+ @data = @data.split('.') if string_or_array.is_a? String
12
+ raise IllegalFormat, to_s unless @data.all? {|item| item.is_a? Integer or item =~ /^\d*$/ }
13
+ @data.map!(&:to_i)
14
+ end
15
+
16
+ def ==(other)
17
+ data == other.data
18
+ end
19
+
20
+ def to_s
21
+ @data.join(".")
22
+ end
23
+
24
+ def apply(diff)
25
+ my_data_r = data.reverse
26
+ diff_data_r = diff.data.reverse
27
+ result = my_data_r.zip(diff_data_r).map do |first, second|
28
+ first = if second =~ /^[+-]/
29
+ first + second.to_i
30
+ else
31
+ (second and second.to_i) or first
32
+ end
33
+ first
34
+ end.reverse
35
+ Version.new(result)
36
+ end
37
+ end
38
+
39
+ class VersionDiff
40
+ IllegalFormat = Class.new(ArgumentError)
41
+
42
+ attr_accessor :data
43
+
44
+ def initialize(string)
45
+ @data = string.split('.')
46
+ raise IllegalFormat, string unless @data.all? {|item| item =~ /^(\+|\-)?\d*$/ }
47
+ end
48
+ end
49
+ end
@@ -0,0 +1 @@
1
+ 0.3.1
@@ -0,0 +1 @@
1
+ 0.3
@@ -0,0 +1,6 @@
1
+ module Gemspec
2
+ class Bump
3
+ VERSION = File.read(File.expand_path("../VERSION", __FILE__))
4
+ VERSION_FOR_HUMANS = File.read(File.expand_path("../VERSION_FOR_HUMANS", __FILE__))
5
+ end
6
+ end
data/rakelib/gem.rake ADDED
@@ -0,0 +1,13 @@
1
+ require 'rubygems/package_task'
2
+ $:.unshift(File.expand_path('../lib',__FILE__))
3
+
4
+ $gemspec = Gem::Specification.load(Dir["*.gemspec"][0])
5
+ files = Rake::FileList.new(Gemspec::Git.ls_files)
6
+
7
+ Gem::PackageTask.new($gemspec) { }
8
+ task :gem => :chmod
9
+ task :chmod do
10
+ files.each do |file|
11
+ chmod 'o+r', file unless File.world_readable?(file)
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ directory "LICENSES"
2
+ $gemspec = Gem::Specification.load(Dir["*.gemspec"][0])
3
+
4
+ file "LICENSES/.info" => "gemspec.gemspec" do |t|
5
+ mkdir_p "LICENSES"
6
+
7
+ licenses_dir = File.expand_path('../../share/gemspec/licenses/', `gem which gemspec`.chomp)
8
+ $? == 0 or licenses_dir = File.expand_path('licenses/')
9
+
10
+ $gemspec.licenses.each do |license|
11
+ cp File.join(licenses_dir, license), "LICENSES/#{Shellwords.escape license}"
12
+ end
13
+ File.write(t.name, "This directory contains the licenses you can use with this gem\n")
14
+ end
15
+
16
+ desc "Fill LICENSES/ with licenses according to gemspec.gemspec and view them"
17
+ task 'license' => 'LICENSES/.info' do
18
+ sh "cd LICENSES/; less *"
19
+ end
@@ -0,0 +1,17 @@
1
+ require 'gemspec/git'
2
+
3
+ desc "Push master to origin, build gem, and push it"
4
+ task 'release' => 'gem' do
5
+ Gemspec::Git.cdroot!
6
+ Gemspec::Git.clean? or (
7
+ warn "Need to clean up before releasing"
8
+ exit 1
9
+ )
10
+ sh "git checkout master"
11
+ s = Gem::Specification.load('gemspec.gemspec')
12
+ sh <<-EOF
13
+ git push origin master &
14
+ rake gem && gem push pkg/#{s.name}-#{s.version}.gem
15
+ wait
16
+ EOF
17
+ end
data/rakelib/test.rake ADDED
@@ -0,0 +1,7 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << "lib" << "test" << "spec"
5
+ t.pattern = 'test/**/*_{test,spec}.rb'
6
+ t.verbose = true
7
+ end
@@ -0,0 +1,64 @@
1
+ require 'minitest_helper'
2
+
3
+ describe "Gemspec::Version" do
4
+ include Gemspec
5
+
6
+ describe "Valid versions" do
7
+
8
+ valid_versions = %w[1.1 1.0.0 443.432.432.432]
9
+ valid_versions.each do |valid_version|
10
+ it "should recognize #{valid_version} as a valid version" do
11
+ Gemspec::Version.new(valid_version)
12
+ end
13
+ end
14
+ end
15
+
16
+ describe "Invalid versions" do
17
+
18
+ invalid_versions = %w[1a.1 fdas1.0.0 443.432.432.432_pre 1.+4.0, -1.3.4 ]
19
+ invalid_versions.each do |valid_version|
20
+ it "should not recognize #{valid_version} as a valid version" do
21
+ assert_raises(Gemspec::Version::IllegalFormat) { Gemspec::Version.new(valid_version) }
22
+ end
23
+ end
24
+ end
25
+
26
+ describe "Applying version diff" do
27
+ #version, diff, result
28
+ [
29
+ %w[1.0.0 1.+1.0 1.1.0],
30
+ %w[1.0.1 1.+1.2 1.1.2],
31
+ %w[1.1.1 1.-1.2 1.0.2],
32
+ %w[1.1.1 +1.2 1.2.2],
33
+ %w[1.1.1.1 +3.+1.2 1.4.2.2],
34
+ ].each do |version, diff, result|
35
+ it "should combine #{version} with #{diff} into #{result}" do
36
+ assert_equal Gemspec::Version.new(result), Gemspec::Version.new(version).apply(Gemspec::VersionDiff.new(diff))
37
+ end
38
+ end
39
+ end
40
+
41
+ end
42
+
43
+ describe "Gemspec::VersionDiff" do
44
+ describe "Valid diffs" do
45
+
46
+ valid_diffs = %w[1.1 1.0.0 443.432.432.432]
47
+ valid_diffs += %w[1.+1 1.-1.0 443.-432.432.+432 -1.0.4]
48
+ valid_diffs.each do |valid_diff|
49
+ it "should recognize #{valid_diff} as a valid diff" do
50
+ Gemspec::VersionDiff.new(valid_diff)
51
+ end
52
+ end
53
+ end
54
+
55
+ describe "Invalid diffs" do
56
+
57
+ invalid_diffs = %w[1a.1 fdas1.0.0 443.432.432.432_pre 1.+a4.0, -a1.3.4 ]
58
+ invalid_diffs.each do |valid_diff|
59
+ it "should not recognize #{valid_diff} as a valid diff" do
60
+ assert_raises(Gemspec::VersionDiff::IllegalFormat) { Gemspec::VersionDiff.new(valid_diff) }
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,11 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+
3
+ $gemspec = Gem::Specification.load(Dir["*.gemspec"][0])
4
+ require $gemspec.name.tr('-','/')
5
+
6
+ require 'minitest/autorun'
7
+ require 'minitest/documentation'
8
+
9
+ Minitest::Test.i_suck_and_my_tests_are_order_dependent!
10
+ Minitest.should_shuffle_suites = false
11
+
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gemspec-bump
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.1
5
+ platform: ruby
6
+ authors:
7
+ - Petr Skocik
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-06-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: gemspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.4'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.4'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest-documentation
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: 'A flexible and concise version bumper that can, in a single command,
56
+ take care of all the git ceremony in a git-flow compatible fashion . '
57
+ email:
58
+ - pskocik@gmail.com
59
+ executables:
60
+ - gemspec-bump
61
+ - versionpatch
62
+ - versionpatch-file
63
+ extensions: []
64
+ extra_rdoc_files: []
65
+ files:
66
+ - ".gitignore"
67
+ - Gemfile
68
+ - README-VERSIONPATCH.md
69
+ - README.md
70
+ - Rakefile
71
+ - VERSION
72
+ - VERSIONING.md
73
+ - VERSION_FOR_HUMANS
74
+ - bin/gemspec-bump
75
+ - bin/versionpatch
76
+ - bin/versionpatch-file
77
+ - gemspec.gemspec
78
+ - lib/gemspec/bump.rb
79
+ - lib/gemspec/bump/VERSION
80
+ - lib/gemspec/bump/VERSION_FOR_HUMANS
81
+ - lib/gemspec/bump/version.rb
82
+ - rakelib/gem.rake
83
+ - rakelib/license.rake
84
+ - rakelib/release.rake
85
+ - rakelib/test.rake
86
+ - test/gemspec-bump_spec.rb
87
+ - test/minitest_helper.rb
88
+ homepage: https://github.com/pjump/gemspec-bump.git
89
+ licenses:
90
+ - GPL-2.0
91
+ metadata:
92
+ namespaced_path: gemspec/bump
93
+ constant_name: Gemspec::Bump
94
+ human_version: |
95
+ 0.3
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubyforge_project:
112
+ rubygems_version: 2.4.6
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: A version bumper
116
+ test_files:
117
+ - test/gemspec-bump_spec.rb
118
+ - test/minitest_helper.rb