seory 0.0.4 → 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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -0
  3. data/Gemfile +1 -0
  4. data/README.md +20 -17
  5. data/lib/seory.rb +25 -4
  6. data/lib/seory/condition.rb +29 -0
  7. data/lib/seory/{page_condition/block_condition.rb → condition/block.rb} +2 -2
  8. data/lib/seory/condition/build_dsl.rb +19 -0
  9. data/lib/seory/{page_condition/params_condition.rb → condition/params.rb} +2 -2
  10. data/lib/seory/{page_condition/path_condition.rb → condition/path.rb} +2 -2
  11. data/lib/seory/{page_condition/slug_condition.rb → condition/slug.rb} +5 -3
  12. data/lib/seory/dsl.rb +12 -49
  13. data/lib/seory/dsl/descriptor.rb +29 -0
  14. data/lib/seory/dsl/page_builder.rb +35 -0
  15. data/lib/seory/page.rb +53 -0
  16. data/lib/seory/page_group.rb +15 -0
  17. data/lib/seory/rails_helper.rb +7 -0
  18. data/lib/seory/railtie.rb +11 -0
  19. data/lib/seory/repository.rb +40 -6
  20. data/lib/seory/runtime.rb +13 -6
  21. data/lib/seory/version.rb +1 -1
  22. data/seory.gemspec +1 -0
  23. data/spec/seory/{page_condition/path_condition_spec.rb → condition/path_spec.rb} +3 -3
  24. data/spec/seory/condition/slug_spec.rb +18 -0
  25. data/spec/seory/dsl_spec.rb +23 -5
  26. data/spec/seory/{page_contents_spec.rb → page_spec.rb} +12 -12
  27. data/spec/seory/rails_helper_spec.rb +62 -0
  28. data/spec/seory/repository_spec.rb +103 -0
  29. data/spec/seory/runtime_spec.rb +25 -6
  30. data/spec/spec_helper.rb +8 -0
  31. data/spec/support/controller_double.rb +37 -0
  32. data/spec/support/testing_dsl.rb +7 -0
  33. data/spec/support/view_context_double.rb +13 -0
  34. metadata +44 -14
  35. data/lib/seory/page_condition.rb +0 -32
  36. data/lib/seory/page_condition/build_dsl.rb +0 -19
  37. data/lib/seory/page_condition/default_condition.rb +0 -10
  38. data/lib/seory/page_contents.rb +0 -41
@@ -0,0 +1,7 @@
1
+ module Seory
2
+ module RailsHelper
3
+ def seory(repository = Seory.default_repository)
4
+ repository.lookup(controller)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ module Seory
2
+ autoload :RailsHelper, 'seory/rails_helper'
3
+
4
+ class Railtie < ::Rails::Railtie
5
+ initializer 'seory' do |app|
6
+ config_dir = (Rails.root + Seory.config_dir)
7
+
8
+ app.config.to_prepare { config_dir.each_child {|src| src.extname == '.rb' && load(src) } }
9
+ end
10
+ end
11
+ end
@@ -1,23 +1,57 @@
1
1
  require 'seory/runtime'
2
2
 
3
3
  module Seory
4
+ class DuplicateDefault < Seory::Error; end
5
+
4
6
  class Repository
7
+ class << self
8
+ def extract_label_from_trace(trace)
9
+ trace.first.split(':').first
10
+ end
11
+ end
12
+
13
+ attr_accessor :helper
14
+
5
15
  def initialize
6
- @store = []
16
+ @page_groups = []
7
17
  end
8
18
 
9
- def <<(page_contents)
10
- @store << page_contents
19
+ def <<(page_group)
20
+ remove_old_group!(page_group.name)
21
+
22
+ @page_groups << page_group
23
+
24
+ clear_page_order_pre_calculation!
11
25
  end
12
26
 
13
27
  def lookup(controller)
14
- page_contents = @store.detect {|page| page.match?(controller) }
28
+ page = pre_orderd_pages.detect {|pg| pg.match?(controller) } || default
15
29
 
16
- Seory::Runtime.new(page_contents, controller, default)
30
+ Seory::Runtime.new(page, controller, default).tap do |runtime|
31
+ runtime.extend helper if helper
32
+ end
17
33
  end
18
34
 
19
35
  def default
20
- @store.detect(&:default?)
36
+ @default ||=
37
+ @page_groups.map(&:default).compact.tap {|defaults|
38
+ raise DuplicateDefault if defaults.size > 1
39
+ }.first
40
+ end
41
+
42
+ private
43
+
44
+ def pre_orderd_pages
45
+ @pre_orderd_pages ||= @page_groups.sort_by(&:name).flat_map(&:pages)
46
+ end
47
+
48
+ def remove_old_group!(page_group_name)
49
+ @page_groups.reject! {|pg| pg.name == page_group_name }
50
+ end
51
+
52
+ def clear_page_order_pre_calculation!
53
+ @pre_orderd_pages = nil
54
+ @default = nil
21
55
  end
22
56
  end
23
57
  end
@@ -1,17 +1,17 @@
1
- # TODO move somewhere
2
- require 'active_support/all'
3
1
  require 'seory'
4
2
 
5
3
  module Seory
6
4
  class Runtime
7
5
  delegate :action_name, to: :controller
8
6
 
9
- attr_reader :controller
7
+ attr_reader :page_contents, :controller
10
8
 
11
9
  def initialize(page_contents, controller, fallback = nil)
12
10
  @page_contents = page_contents
13
11
  @controller = controller
14
12
  @fallback = fallback
13
+
14
+ extend build_assign_accessor_module(@page_contents.assign_name_accessors)
15
15
  end
16
16
 
17
17
  def assigns(name)
@@ -30,14 +30,12 @@ module Seory
30
30
 
31
31
  def calculate_content_for(name)
32
32
  case page_content = lookup_content_for(name)
33
- when String
34
- page_content
35
33
  when Symbol
36
34
  calculate_content_for(page_content)
37
35
  when ->(o) { o.respond_to?(:call) }
38
36
  instance_exec(&page_content)
39
37
  else
40
- raise 'BUG'
38
+ page_content.to_s
41
39
  end
42
40
  end
43
41
 
@@ -45,5 +43,14 @@ module Seory
45
43
  @page_contents.content_for(name) || \
46
44
  @fallback.try {|fb| fb.content_for(name) }
47
45
  end
46
+
47
+ def build_assign_accessor_module(names)
48
+ Module.new do
49
+ Array(names).each do |name|
50
+ define_method(name) { assigns(name) }
51
+ end
52
+ end
53
+ end
54
+
48
55
  end
49
56
  end
@@ -1,3 +1,3 @@
1
1
  module Seory
2
- VERSION = "0.0.4"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency "activesupport", "> 3.2"
22
+ spec.add_dependency "railties", "> 3.2"
22
23
 
23
24
  spec.add_development_dependency "bundler", "~> 1.6"
24
25
  spec.add_development_dependency "rake"
@@ -1,10 +1,10 @@
1
1
  require 'spec_helper'
2
- require 'seory/page_condition/path_condition'
2
+ require 'seory/condition/path'
3
3
 
4
- describe Seory::PageCondition::PathCondition do
4
+ describe Seory::Condition::Path do
5
5
  let(:controller) { double('controller') }
6
6
  let(:path_condition) do
7
- Seory::PageCondition::PathCondition.new('/users/alice')
7
+ Seory::Condition::Path.new('/users/alice')
8
8
  end
9
9
 
10
10
  context 'Accessed to /users/alice (controller: users, action: show, id: alice)' do
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+ require 'seory/condition/slug'
3
+
4
+ describe Seory::Condition::Slug do
5
+ context 'with nested controller slug' do
6
+ let(:controller) do
7
+ double('controller', {
8
+ controller_name: 'products',
9
+ controller_path: 'contents/products',
10
+ action_name: 'index'
11
+ })
12
+ end
13
+ let(:slug_condition) { Seory::Condition::Slug.new('contents/products#index') }
14
+
15
+ specify { expect(slug_condition.match?(controller)).to be_truthy }
16
+ end
17
+ end
18
+
@@ -7,7 +7,7 @@ describe Seory::Dsl do
7
7
  context 'with traditional syntax' do
8
8
  let(:seory_class) { Object.new.extend(Seory::Dsl) }
9
9
  before do
10
- seory_class.describe do
10
+ seory_class.describe('Group A') do
11
11
  match ->(c) { c.controller_name == 'reports' } do
12
12
  title 'Useful reports'
13
13
  end
@@ -30,13 +30,13 @@ describe Seory::Dsl do
30
30
  end
31
31
 
32
32
  context 'at reports#index / match with proc' do
33
- let(:controller) { double('controller', controller_name: 'reports', action_name: 'index') }
33
+ let(:controller) { double('controller', controller_name: 'reports', controller_path: 'reports', action_name: 'index') }
34
34
 
35
35
  specify { expect(seory.title).to eq 'Useful reports' }
36
36
  end
37
37
 
38
38
  context 'at products#index' do
39
- let(:controller) { double('controller', controller_name: 'products', action_name: 'index') }
39
+ let(:controller) { double('controller', controller_name: 'products', controller_path: 'products', action_name: 'index') }
40
40
 
41
41
  specify { expect(seory.title).to eq 'My Great Product' }
42
42
  specify { expect(seory.h1).to eq 'Great Product Name' }
@@ -46,13 +46,31 @@ describe Seory::Dsl do
46
46
  end
47
47
 
48
48
  context 'at misc#show' do
49
- let(:controller) { double('controller', controller_name: 'misc', action_name: 'show') }
49
+ let(:controller) { double('controller', controller_name: 'misc', controller_path: 'misc', action_name: 'show') }
50
50
 
51
51
  specify { expect(seory.h1).to eq 'MISC' }
52
52
  specify { expect(seory.misc(:option)).to eq 'dynamic option name at misc' }
53
53
  end
54
54
  end
55
55
 
56
+ context 'accessor to assign' do
57
+ let(:seory_class) { Object.new.extend(Seory::Dsl) }
58
+ let(:controller) do
59
+ controller_double('products#show') { @product = OpenStruct.new(name: 'seory') }
60
+ end
61
+
62
+ before do
63
+ seory_class.describe do
64
+ match slug('products#show') do
65
+ assign_reader :product
66
+ title { product.name }
67
+ end
68
+ end
69
+ end
70
+
71
+ specify { expect(seory.title).to eq 'seory' }
72
+ end
73
+
56
74
  context 'with matcher build dsl syntax' do
57
75
  let(:seory_class) { Object.new.extend(Seory::Dsl) }
58
76
  before do
@@ -69,7 +87,7 @@ describe Seory::Dsl do
69
87
 
70
88
  context 'at products#show' do
71
89
  let(:controller) do
72
- double('controller', controller_name: 'products', action_name: 'show', params: {id: 42}).tap do |c|
90
+ double('controller', controller_name: 'products', controller_path: 'products', action_name: 'show', params: {id: 42}).tap do |c|
73
91
  allow(c).to receive_message_chain(:request, :fullpath) { '/products/42' }
74
92
  end
75
93
  end
@@ -1,14 +1,14 @@
1
1
  require 'spec_helper'
2
- require 'seory/page_contents'
2
+ require 'seory/page'
3
3
 
4
- describe Seory::PageContents do
4
+ describe Seory::Page do
5
5
  specify 'cant define without condition' do
6
- expect { Seory::PageContents.new }.to raise_error(Seory::EmptyCondition)
6
+ expect { Seory::Page.new }.to raise_error(Seory::EmptyCondition)
7
7
  end
8
8
 
9
- context 'content PageContents' do
9
+ context 'content Page' do
10
10
  let(:seory_def) do
11
- Seory::PageContents.new(:default)
11
+ Seory::Page.new(:default)
12
12
  end
13
13
 
14
14
  context 'define static content' do
@@ -40,16 +40,16 @@ describe Seory::PageContents do
40
40
 
41
41
  describe 'condition and #match?' do
42
42
  def init_with(*args, &block)
43
- Seory::PageContents.new(*args, &block)
43
+ Seory::Page.new(*args, &block)
44
44
  end
45
45
 
46
- let(:controller) { double('controller', controller_name: 'people', action_name: 'index') }
46
+ let(:controller) { double('controller', controller_path: 'people', action_name: 'index') }
47
47
 
48
48
  specify '`:default` matches everything (stacked in bottom)' do
49
49
  expect(init_with(:default)).to be_match(double('something'))
50
50
  end
51
51
 
52
- describe 'controller_name#action_name' do
52
+ describe 'controller_path#action_name' do
53
53
  specify do
54
54
  expect(init_with('people#index').match?(controller)).to be_truthy
55
55
  end
@@ -63,7 +63,7 @@ describe Seory::PageContents do
63
63
  end
64
64
 
65
65
  specify do
66
- page_contents = init_with {|c| c.controller_name == 'people' }
66
+ page_contents = init_with {|c| c.controller_path == 'people' }
67
67
 
68
68
  expect(page_contents.match?(controller)).to be_truthy
69
69
  end
@@ -102,17 +102,17 @@ describe Seory::PageContents do
102
102
 
103
103
  describe 'proc conditions' do
104
104
  let(:page_content) do
105
- init_with {|c| c.controller_name == 'users' }
105
+ init_with {|c| c.controller_path == 'users' }
106
106
  end
107
107
 
108
108
  specify 'match UsersController' do
109
- allow(controller).to receive(:controller_name) { 'users' }
109
+ allow(controller).to receive(:controller_path) { 'users' }
110
110
 
111
111
  expect(page_content.match?(controller)).to be_truthy
112
112
  end
113
113
 
114
114
  specify 'not match GoodsController' do
115
- allow(controller).to receive(:controller_name) { 'goods' }
115
+ allow(controller).to receive(:controller_path) { 'goods' }
116
116
 
117
117
  expect(page_content.match?(controller)).to be_falsy
118
118
  end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+ require 'seory'
3
+
4
+ describe Seory::RailsHelper do
5
+ before do
6
+ Seory.seo_content 'products' do
7
+ match slug('products#index') do
8
+ title 'Product index'
9
+ end
10
+
11
+ default do
12
+ title 'Default title'
13
+ end
14
+ end
15
+
16
+ Seory.seo_content 'Review for products' do
17
+ match slug('products/reviews#index') do
18
+ assign_reader :product
19
+
20
+ title { "Reviews for #{bang(product.name)}" }
21
+ end
22
+ end
23
+
24
+ Seory.helper do
25
+ def bang(string); string + ' !!!'; end
26
+ end
27
+ end
28
+
29
+ context 'GET /products' do
30
+ let(:context) do
31
+ Seory::ViewContextDouble.new(controller_double('products#index'))
32
+ end
33
+
34
+ specify do
35
+ expect(context.seory.title).to eq 'Product index'
36
+ end
37
+ end
38
+
39
+ context 'GET /products/a-computer/reviews' do
40
+ let(:context) do
41
+ controller = controller_double('products/reviews#index') do
42
+ @product = OpenStruct.new(name: 'a-computer')
43
+ end
44
+
45
+ Seory::ViewContextDouble.new(controller)
46
+ end
47
+
48
+ specify do
49
+ expect(context.seory.title).to eq "Reviews for a-computer !!!"
50
+ end
51
+ end
52
+
53
+ context 'GET /users' do
54
+ let(:context) do
55
+ Seory::ViewContextDouble.new(controller_double('users#index'))
56
+ end
57
+
58
+ specify do
59
+ expect(context.seory.title).to eq 'Default title'
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,103 @@
1
+ require 'spec_helper'
2
+ require 'seory/repository'
3
+ require 'seory/dsl/descriptor'
4
+
5
+ describe Seory::Repository do
6
+ let(:repository) { Seory::Repository.new }
7
+
8
+ describe '.extract_label_from_trace' do
9
+ let(:label) do
10
+ begin
11
+ raise
12
+ rescue => ex
13
+ Seory::Repository.extract_label_from_trace(ex.backtrace)
14
+ end
15
+ end
16
+
17
+ specify { expect(label).to eq __FILE__ }
18
+ end
19
+
20
+ def title_for(*args)
21
+ repository.lookup(controller_double(*args)).title
22
+ end
23
+
24
+ def page_group(name, title = name)
25
+ describe_page_group(name) do
26
+ match(slug("#{name}#show")) { title title }
27
+ end
28
+ end
29
+
30
+ def describe_page_group(name, &block)
31
+ Seory::Dsl::Descriptor.new(name, repository).describe(&block)
32
+ end
33
+
34
+ context 'has 2 page groups: users & products' do
35
+ before do
36
+ repository << page_group('users')
37
+ repository << page_group('products')
38
+ end
39
+
40
+ specify 'lookup valid page over page_groups' do
41
+ expect(title_for('users#show', id: 42)).to eq 'users'
42
+ expect(title_for('products#show', id: 42)).to eq 'products'
43
+ end
44
+
45
+ context 'overrides same name group' do
46
+ before do
47
+ repository << page_group('users', 'other users')
48
+ end
49
+
50
+ specify 'after one should be used' do
51
+ expect(title_for('users#show', id: 42)).to eq 'other users'
52
+ end
53
+ end
54
+
55
+ context 'match controller by PageGroup#name sorted' do
56
+ before do
57
+ repository << (
58
+ Seory::Dsl::Descriptor.new('aaa', repository).describe do
59
+ match(params(controller: 'users')) { title 'defined after, match ahead' }
60
+ end
61
+ )
62
+ end
63
+
64
+ specify do
65
+ expect(title_for('users#show', id: 42)).to eq 'defined after, match ahead'
66
+ end
67
+ end
68
+ end
69
+
70
+ describe 'helper integration' do
71
+ before do
72
+ repository << describe_page_group('default') { default { title { upcase('title') }} }
73
+ repository.helper = Module.new do
74
+ def upcase(string); string.upcase; end
75
+ end
76
+ end
77
+
78
+ specify do
79
+ expect(title_for('hoge#foo')).to eq 'TITLE'
80
+ end
81
+ end
82
+
83
+ describe 'default fallback' do
84
+ context 'default is used from any page group' do
85
+ before do
86
+ repository << page_group('users')
87
+ repository << describe_page_group('default') { default { title 'default title' } }
88
+ end
89
+
90
+ specify do
91
+ expect(title_for('hoge#foo')).to eq 'default title'
92
+ end
93
+
94
+ specify 'default can be specified from only one page group or raise DuplicateDefault' do
95
+ expect {
96
+ repository << describe_page_group('duplicate default') { default { title 'duplicate default' } }
97
+
98
+ repository.lookup(controller_double('hi#index'))
99
+ }.to raise_error(Seory::DuplicateDefault)
100
+ end
101
+ end
102
+ end
103
+ end