stateful_field_for 0.1.0

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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 00e7a7cbc4bee02957da2fa1a4f4d898747a6aad
4
+ data.tar.gz: f760d30c688490fbd49db1be2d16f792cb084ccc
5
+ SHA512:
6
+ metadata.gz: e33b5b26affe43e1b4cac65ff6ef010f7fa6459c46ed8cbbf88e37b8ade7809063293245e49d1627da80cbf2d327164768a22435cb26a3ed80af490b9e2f1a92
7
+ data.tar.gz: 5fbd107d095b9a6122d8e3a38d2ea37a6c5ff0dcfed1cf4e5542cb49dc7851caedd8ea9cfc2b29e2ceaa2980c07cb113aa297c2fd1793548361d3f5c610c01b3
@@ -0,0 +1,50 @@
1
+ # StatefulFieldFor
2
+
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
4
+
5
+ Provide the bang and predicate methods for Active Record.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem "stateful_field_for"
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install stateful_field_for
22
+
23
+ ## Usage
24
+
25
+ ```diff
26
+ class Picture < ApplicationRecord
27
+ + stateful_field_for :hidden_at, scope: true do
28
+ + enable :hide, to: :hidden
29
+ + disable :show, to: :visible, initial: true
30
+ + end
31
+ end
32
+ ```
33
+
34
+ Then you can use the bang and predicate methods:
35
+
36
+ ```ruby
37
+ picture = Picture.create
38
+
39
+ picture.show!
40
+ picture.hidden? # false
41
+ picture.visible? # true
42
+
43
+ picture.hide!
44
+ picture.hidden? # true
45
+ picture.visible? # false
46
+ ```
47
+
48
+ ## License
49
+
50
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,13 @@
1
+ require "stateful_field_for/version"
2
+
3
+ module StatefulFieldFor
4
+ def stateful_field_for(attr_name, options = {}, &block)
5
+ definition = Definition.new(attr_name, options)
6
+ definition.instance_eval(&block)
7
+ const_set definition.module_name, definition._module
8
+ include definition._module
9
+ end
10
+ end
11
+
12
+ require "stateful_field_for/definition"
13
+ require "stateful_field_for/railtie" if defined?(Rails)
@@ -0,0 +1,97 @@
1
+ module StatefulFieldFor
2
+ class Definition
3
+ attr_reader :attr_name, :prefix, :suffix, :scope, :logic
4
+
5
+ def initialize(attr_name, options = {})
6
+ @attr_name = attr_name
7
+ @prefix = options[:prefix]
8
+ @suffix = options[:suffix]
9
+ @scope = options[:scope] || false
10
+ @logic = (options[:type] == :date) ? "Date.today" : "Time.current"
11
+ end
12
+
13
+ def _module
14
+ @_module ||= Module.new do
15
+ def self.included(klass)
16
+ __define_scope_for_activate(klass) if respond_to?(:__define_scope_for_activate)
17
+ __define_scope_for_deactivate(klass) if respond_to?(:__define_scope_for_deactivate)
18
+ __define_after_initialize(klass) if respond_to?(:__define_after_initialize)
19
+ end
20
+ end
21
+ end
22
+
23
+ def module_name
24
+ "generated_#{attr_name}_stateful_methods".split("_").map(&:camelize).join
25
+ end
26
+
27
+ private
28
+
29
+ def enable(event_basename, to: nil, initial: false)
30
+ event = format_name(event_basename)
31
+ state = to.nil? ? event : format_name(to)
32
+
33
+ _module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
34
+ def #{state}?
35
+ !#{attr_name}.nil?
36
+ end
37
+
38
+ def #{event}
39
+ self.#{attr_name} = #{logic}
40
+ end
41
+
42
+ def #{event}!(options = {})
43
+ #{event}
44
+ save!(options)
45
+ end
46
+ RUBY
47
+
48
+ _module.module_eval <<-RUBY, __FILE__, __LINE__ + 1 if scope
49
+ def self.__define_scope_for_activate(klass)
50
+ klass.scope :#{state}, -> { where.not(#{attr_name}: nil) }
51
+ end
52
+ RUBY
53
+
54
+ _module.module_eval <<-RUBY, __FILE__, __LINE__ + 1 if initial
55
+ def self.__define_after_initialize(klass)
56
+ klass.after_initialize :#{event}
57
+ end
58
+ RUBY
59
+ end
60
+
61
+ def disable(event_basename, to: nil, initial: false)
62
+ event = format_name(event_basename)
63
+ state = to.nil? ? event : format_name(to)
64
+
65
+ _module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
66
+ def #{state}?
67
+ #{attr_name}.nil?
68
+ end
69
+
70
+ def #{event}
71
+ self.#{attr_name} = nil
72
+ end
73
+
74
+ def #{event}!(options = {})
75
+ #{event}
76
+ save!(options)
77
+ end
78
+ RUBY
79
+
80
+ _module.module_eval <<-RUBY, __FILE__, __LINE__ + 1 if scope
81
+ def self.__define_scope_for_deactivate(klass)
82
+ klass.scope :#{state}, -> { where(#{attr_name}: nil) }
83
+ end
84
+ RUBY
85
+
86
+ _module.module_eval <<-RUBY, __FILE__, __LINE__ + 1 if initial
87
+ def self.__define_after_initialize(klass)
88
+ klass.after_initialize :#{event}
89
+ end
90
+ RUBY
91
+ end
92
+
93
+ def format_name(basename)
94
+ [prefix, basename, suffix].compact.join("_")
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,9 @@
1
+ module StatefulFieldFor
2
+ class Railtie < ::Rails::Railtie
3
+ initializer :stateful_field_for do
4
+ ActiveSupport.on_load :active_record do
5
+ extend StatefulFieldFor
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module StatefulFieldFor
2
+ VERSION = "0.1.0".freeze
3
+ end
@@ -0,0 +1,37 @@
1
+ require "active_record"
2
+ require "action_controller"
3
+ require "stateful_field_for"
4
+
5
+ ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
6
+
7
+ module FakeApp
8
+ class Application < Rails::Application
9
+ config.eager_load = false
10
+ end
11
+ end
12
+
13
+ FakeApp::Application.initialize!
14
+
15
+ class CreateTables < ActiveRecord::Migration[5.1]
16
+ def change
17
+ create_table :pictures do |t|
18
+ t.string :title
19
+ t.datetime :published_at
20
+ t.datetime :hidden_at
21
+
22
+ t.timestamps
23
+ end
24
+ end
25
+ end
26
+
27
+ class Picture < ActiveRecord::Base
28
+ stateful_field_for :published_at, scope: true do
29
+ enable :publish, to: :published, initial: true
30
+ disable :unpublish, to: :unpublished
31
+ end
32
+
33
+ stateful_field_for :hidden_at do
34
+ enable :hide, to: :hidden
35
+ disable :show, to: :visible
36
+ end
37
+ end
@@ -0,0 +1 @@
1
+ run Rails.application
File without changes
@@ -0,0 +1,85 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Picture do
4
+ context "scope" do
5
+ let!(:published_records) { Array.new(3) { Picture.create(published_at: Time.current) } }
6
+ let!(:unpublished_records) { Array.new(3) { Picture.create.tap(&:unpublish!) } }
7
+
8
+ describe ".published" do
9
+ subject { Picture.published.pluck(:id) }
10
+ it { is_expected.to match_array published_records.map(&:id) }
11
+ end
12
+
13
+ describe ".unpublished" do
14
+ subject { Picture.unpublished.pluck(:id) }
15
+ it { is_expected.to match_array unpublished_records.map(&:id) }
16
+ end
17
+ end
18
+
19
+ context "callback" do
20
+ let(:instance) { Picture.new }
21
+ subject { instance.published? }
22
+ it { is_expected.to be true }
23
+ end
24
+
25
+ context "predicate" do
26
+ let(:published) { Picture.new(published_at: Time.current) }
27
+ let(:unpublished) { Picture.new.tap(&:unpublish) }
28
+ let(:hidden) { Picture.new(hidden_at: Time.current) }
29
+ let(:visible) { Picture.new(hidden_at: nil) }
30
+
31
+ describe "#published?" do
32
+ it { expect(published.published?).to be true }
33
+ it { expect(unpublished.published?).to be false }
34
+ end
35
+
36
+ describe "#unpublished?" do
37
+ it { expect(unpublished.unpublished?).to be true }
38
+ it { expect(published.unpublished?).to be false }
39
+ end
40
+
41
+ describe "#hidden?" do
42
+ it { expect(hidden.hidden?).to be true }
43
+ it { expect(visible.hidden?).to be false }
44
+ end
45
+
46
+ describe "#visible?" do
47
+ it { expect(visible.visible?).to be true }
48
+ it { expect(hidden.visible?).to be false }
49
+ end
50
+ end
51
+
52
+ context "bang" do
53
+ let(:published) { Picture.new(published_at: Time.current) }
54
+ let(:hidden) { Picture.new(hidden_at: Time.current) }
55
+ let(:visible) { Picture.new(hidden_at: nil) }
56
+
57
+ describe "#publish!" do
58
+ let(:instance) { Picture.new(published_at: nil) }
59
+ before { instance.publish! }
60
+ it { expect(instance.published?).to be true }
61
+ it { expect(instance.persisted?).to be true }
62
+ end
63
+
64
+ describe "#unpublish!" do
65
+ let(:instance) { Picture.new(published_at: Time.current) }
66
+ before { instance.unpublish! }
67
+ it { expect(instance.unpublished?).to be true }
68
+ it { expect(instance.persisted?).to be true }
69
+ end
70
+
71
+ describe "#hide!" do
72
+ let(:instance) { Picture.new(hidden_at: nil) }
73
+ before { instance.hide! }
74
+ it { expect(instance.hidden?).to be true }
75
+ it { expect(instance.persisted?).to be true }
76
+ end
77
+
78
+ describe "#show!" do
79
+ let(:instance) { Picture.new(hidden_at: Time.current) }
80
+ before { instance.show! }
81
+ it { expect(instance.visible?).to be true }
82
+ it { expect(instance.persisted?).to be true }
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,22 @@
1
+ require "bundler/setup"
2
+ # load Rails first
3
+ require "rails"
4
+
5
+ # needs to load the app next
6
+ require_relative "fake_app/application"
7
+
8
+ require "stateful_field_for"
9
+ require "rspec/rails"
10
+ require "pry"
11
+
12
+ RSpec.configure do |config|
13
+ config.example_status_persistence_file_path = ".rspec_status"
14
+ config.disable_monkey_patching!
15
+ config.use_transactional_fixtures = true
16
+
17
+ config.expect_with :rspec do |c|
18
+ c.syntax = :expect
19
+ end
20
+ end
21
+
22
+ CreateTables.migrate(:up) unless ActiveRecord::Base.connection.table_exists?("pictures")
@@ -0,0 +1,7 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe StatefulFieldFor do
4
+ it "has a version number" do
5
+ expect(StatefulFieldFor::VERSION).not_to be nil
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stateful_field_for
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Yoshiyuki Hirano
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-10-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: railties
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '5.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.15'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.15'
41
+ description: Provide the bang and predicate methods for Active Record
42
+ email:
43
+ - yhirano@me.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - README.md
49
+ - Rakefile
50
+ - lib/stateful_field_for.rb
51
+ - lib/stateful_field_for/definition.rb
52
+ - lib/stateful_field_for/railtie.rb
53
+ - lib/stateful_field_for/version.rb
54
+ - spec/fake_app/application.rb
55
+ - spec/fake_app/config.ru
56
+ - spec/fake_app/log/development.log
57
+ - spec/model_spec.rb
58
+ - spec/spec_helper.rb
59
+ - spec/stateful_field_for_spec.rb
60
+ homepage: https://github.com/yhirano55/stateful_field_for
61
+ licenses:
62
+ - MIT
63
+ metadata: {}
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 2.2.0
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubyforge_project:
80
+ rubygems_version: 2.6.13
81
+ signing_key:
82
+ specification_version: 4
83
+ summary: Provide the bang and predicate methods for Active Record
84
+ test_files:
85
+ - spec/fake_app/application.rb
86
+ - spec/fake_app/config.ru
87
+ - spec/fake_app/log/development.log
88
+ - spec/model_spec.rb
89
+ - spec/spec_helper.rb
90
+ - spec/stateful_field_for_spec.rb