seory 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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