33Page Object Projects (POP)
44==========================
55
6- **POPs ** are way to package up a group of Page Objects together so they
7- can be used in other projects as well. This improves code reusability since
8- the extraction logic in some web pages are easily shareable. More importantly,
6+ **POPs ** are a way to standardize how a group of Page Objects are packaged
7+ together so they can be uniformly used in other projects. More importantly,
98**POPs ** could be built using other **POPs **. This allows for continuous
109improvements by building **POPs ** on top of one another.
1110
1211Organizing POP
1312--------------
1413
1514Developers have complete freedom on how to organize their Page Objects
16- in their project . Here are some options that developers could use.
15+ in their projects . Here are some of the options that developers could use.
1716
1817Flat Hierarchy
1918~~~~~~~~~~~~~~
@@ -61,10 +60,11 @@ domains. This could easily be grouped as something like:
6160 | | | ├── products.py
6261 | | | └── product_listings.py
6362 | | └── __init__.py
64- | └── furniture_shop
65- | ├── __init__.py
66- | ├── products.py
67- | └── product_listings.py
63+ | ├── furniture_shop
64+ | | ├── __init__.py
65+ | | ├── products.py
66+ | | └── product_listings.py
67+ | └── __init__.py
6868 └── setup.py
6969
7070 Requirements for POP
@@ -85,7 +85,7 @@ This covers the basic use case:
8585 - Importing the Page Objects directly from the installed package in a project.
8686
8787
88- This translates into **POPs ** needing to have:
88+ This means that **POPs ** need to have:
8989
9090 - The ``setup.py `` script which is the standard way of distributing Python packages.
9191
@@ -114,32 +114,32 @@ by simply importing them:
114114
115115 from ecommerce_page_objects.furniture_shop.products import FurnitureProductPage
116116
117- response_data = download_response(" https://www.furnitureshop.com/product/xyz" )
118- page = FurnitureProductPage()
117+ response = download_response(" https://www.furnitureshop.com/product/xyz" )
118+ page = FurnitureProductPage(response )
119119 item = page.to_item()
120120
121121 Recommended Requirements
122122~~~~~~~~~~~~~~~~~~~~~~~~
123123
124- This covers these use use cases:
124+ This covers these use cases:
125125
126- - The minimum requirements and use cases stated above
126+ - The minimum requirements and its use cases
127127 - The ability to retrieve the declared :class: `~.OverrideRule `
128128 inside the **POP **
129129
130- This means that a list of :class: `~.OverrideRule ` must be explicitly
130+ This means that a collection of :class: `~.OverrideRule ` must be explicitly
131131declared in the **POP **. This enables projects using the **POP ** to know:
132132
133133 - which URL Patterns a given Page Object is expected to work
134134 - what it's trying to override `(or replace) `
135135
136- This could be done by declaring a ``RULES `` variable that can be
136+ This could be done by declaring a ``REGISTRY `` variable that can be
137137imported as a top-level variable from the package.
138138
139139For example, suppose our project is named **ecommerce_page_objects **
140- and is using either of the project structure options discussed in the
141- previous sections, then we can define the ``RULES `` as the following
142- inside `` ecommerce_page_objects /ecommerce_page_objects/__init__.py ``.
140+ and is using any of the project structure options discussed in the
141+ previous sections, we can then define the ``REGISTRY `` variable as the following
142+ inside of `` ecommerce-page-objects /ecommerce_page_objects/__init__.py ``:
143143
144144.. code-block :: python
145145
@@ -148,19 +148,32 @@ inside ``ecommerce_page_objects/ecommerce_page_objects/__init__.py``.
148148 # This allows all of the OverrideRules declared inside the package
149149 # using @handle_urls to be properly discovered and loaded.
150150 consume_modules(__package__ )
151- RULES = default_registry.get_overrides()
152151
153- This allows any developer using a **POP ** to easily get the list of
152+ REGISTRY = default_registry
153+
154+ This allows any developer using a **POP ** to easily access all of the
154155:class: `~.OverrideRule ` using the convention of accessing it via the
155- ``RULES `` variable as a top-level variable :
156+ ``REGISTRY `` variable. For example :
156157
157158.. code-block :: python
158159
159- from ecommerce_page_objects import RULES
160+ from ecommerce_page_objects import REGISTRY
161+
162+ .. tip ::
163+
164+ The ``default_registry `` is an instance of :class: `~.PageObjectRegistry `,
165+ which in turn is simply a subclass of a ``dict ``. This means that you don't
166+ necessarily have to use an instance of :class: `~.PageObjectRegistry ` as long
167+ as it has a ``dict ``-like interface.
160168
161- There may be some circumstances that needs other ways of declaring this.
162- For such cases, developers/maintainers of **POPs ** must reflect that
163- clearly in the documentation.
169+ The :class: `~.PageObjectRegistry ` is simply a mapping where the **key ** is
170+ the Page Object to use and the **value ** is the :class: `~.OverrideRule ` it
171+ operates on. This means you can simply use a plain ``dict `` for the
172+ ``REGISTRY `` variable.
173+
174+ However, it is **recommended ** to use the instances of
175+ :class: `~.PageObjectRegistry ` to leverage the validation logic for its
176+ contents.
164177
165178
166179Conventions and Best Practices
@@ -170,7 +183,7 @@ Conventions and Best Practices
170183 This allows for easy identification when used by other developers.
171184
1721852. The list of :class: `~.OverrideRule ` must be declared as a top-level
173- variable from the package named ``RULES ``. This enables other developers
186+ variable from the package named ``REGISTRY ``. This enables other developers
174187 to easily retrieve the list of :class: `~.OverrideRule ` to be used in
175188 their own projects.
176189
@@ -179,6 +192,10 @@ Conventions and Best Practices
179192 :class: `~.PageObjectRegistry `. This provides a default expectation
180193 for developers on which registry to use right from the start.
181194
195+ * However, there will be some cases where creating a new instance of
196+ :class: `~.PageObjectRegistry ` is inevitably needed. Here's an
197+ :ref: `example <overrides-custom-registry >` in the tutorial section.
198+
1821994. When building a new **POP ** based of on existing **POPs **, it is
183200 recommended to use an **inclusion ** strategy rather than **exclusion **
184201 when selecting the list of :class: `~.OverrideRule ` to export.
0 commit comments